summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/actions/setup/directories/action.yml2
-rw-r--r--.github/workflows/annocheck.yml8
-rw-r--r--.github/workflows/baseruby.yml8
-rw-r--r--.github/workflows/bundled_gems.yml2
-rw-r--r--.github/workflows/check_dependencies.yml8
-rw-r--r--.github/workflows/check_misc.yml2
-rw-r--r--.github/workflows/codeql-analysis.yml14
-rw-r--r--.github/workflows/compilers.yml8
-rw-r--r--.github/workflows/dependabot_automerge.yml2
-rw-r--r--.github/workflows/macos.yml4
-rw-r--r--.github/workflows/mingw.yml8
-rw-r--r--.github/workflows/prism.yml4
-rw-r--r--.github/workflows/rjit-bindgen.yml8
-rw-r--r--.github/workflows/rjit.yml2
-rw-r--r--.github/workflows/scorecards.yml6
-rw-r--r--.github/workflows/spec_guards.yml4
-rw-r--r--.github/workflows/ubuntu.yml6
-rw-r--r--.github/workflows/wasm.yml12
-rw-r--r--.github/workflows/windows.yml8
-rw-r--r--.github/workflows/yjit-macos.yml9
-rw-r--r--.github/workflows/yjit-ubuntu.yml18
-rw-r--r--.gitignore3
-rw-r--r--NEWS.md18
-rw-r--r--array.c14
-rw-r--r--ast.c308
-rwxr-xr-xbootstraptest/runner.rb30
-rw-r--r--bootstraptest/test_ractor.rb21
-rw-r--r--bootstraptest/test_yjit.rb194
-rw-r--r--common.mk145
-rw-r--r--compile.c125
-rw-r--r--configure.ac25
-rw-r--r--cont.c3
-rw-r--r--defs/gmake.mk4
-rw-r--r--dln.c46
-rw-r--r--dln.h3
-rw-r--r--dmydln.c15
-rw-r--r--doc/contributing/building_ruby.md6
-rw-r--r--doc/encodings.rdoc2
-rw-r--r--doc/extension.ja.rdoc5
-rw-r--r--doc/extension.rdoc11
-rw-r--r--doc/globals.rdoc2
-rw-r--r--doc/syntax/pattern_matching.rdoc8
-rw-r--r--enc/depend66
-rw-r--r--enc/encinit.c.erb3
-rwxr-xr-xenc/make_encmake.rb8
-rw-r--r--encoding.c16
-rw-r--r--enum.c221
-rw-r--r--error.c31
-rw-r--r--ext/-test-/RUBY_ALIGNOF/depend1
-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-/bignum/depend7
-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-/debug/depend3
-rw-r--r--ext/-test-/dln/empty/depend1
-rw-r--r--ext/-test-/enumerator_kw/depend1
-rw-r--r--ext/-test-/exception/depend4
-rw-r--r--ext/-test-/fatal/depend5
-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/depend3
-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_target/resolve_symbol_target.h2
-rw-r--r--ext/-test-/load/stringify_target/stringify_target.h2
-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-/printf/depend1
-rw-r--r--ext/-test-/proc/depend3
-rw-r--r--ext/-test-/random/depend3
-rw-r--r--ext/-test-/rational/depend1
-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-/scan_args/depend1
-rw-r--r--ext/-test-/st/foreach/depend1
-rw-r--r--ext/-test-/st/numhash/depend1
-rw-r--r--ext/-test-/st/update/depend1
-rw-r--r--ext/-test-/string/depend18
-rw-r--r--ext/-test-/struct/depend5
-rw-r--r--ext/-test-/symbol/depend2
-rw-r--r--ext/-test-/thread/instrumentation/depend1
-rw-r--r--ext/-test-/thread_fd/depend1
-rw-r--r--ext/-test-/time/depend3
-rw-r--r--ext/-test-/tracepoint/depend2
-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/cgi/escape/depend1
-rw-r--r--ext/continuation/depend1
-rw-r--r--ext/coverage/depend1
-rw-r--r--ext/date/depend4
-rw-r--r--ext/digest/bubblebabble/depend1
-rw-r--r--ext/digest/depend1
-rw-r--r--ext/digest/md5/depend2
-rw-r--r--ext/digest/rmd160/depend2
-rw-r--r--ext/digest/sha1/depend2
-rw-r--r--ext/digest/sha2/depend2
-rw-r--r--ext/etc/depend1
-rwxr-xr-xext/extmk.rb1
-rw-r--r--ext/fcntl/depend1
-rw-r--r--ext/fiddle/depend8
-rw-r--r--ext/io/console/depend1
-rw-r--r--ext/io/nonblock/depend1
-rw-r--r--ext/io/wait/depend1
-rw-r--r--ext/json/generator/depend1
-rw-r--r--ext/json/parser/depend1
-rw-r--r--ext/monitor/depend1
-rw-r--r--ext/objspace/depend3
-rw-r--r--ext/openssl/depend33
-rw-r--r--ext/openssl/lib/openssl/buffering.rb17
-rw-r--r--ext/openssl/lib/openssl/ssl.rb26
-rw-r--r--ext/openssl/ossl_asn1.c7
-rw-r--r--ext/openssl/ossl_cipher.c22
-rw-r--r--ext/openssl/ossl_digest.c33
-rw-r--r--ext/openssl/ossl_pkcs7.c28
-rw-r--r--ext/openssl/ossl_ssl.c8
-rw-r--r--ext/openssl/ossl_ts.c60
-rw-r--r--ext/pathname/depend1
-rw-r--r--ext/psych/depend5
-rw-r--r--ext/pty/depend1
-rw-r--r--ext/rbconfig/sizeof/depend2
-rw-r--r--ext/ripper/depend4
-rw-r--r--ext/ripper/ripper_init.c.tmpl74
-rw-r--r--ext/ripper/tools/dsl.rb6
-rw-r--r--ext/ripper/tools/generate.rb6
-rw-r--r--ext/ripper/tools/preproc.rb57
-rw-r--r--ext/socket/depend15
-rw-r--r--ext/stringio/depend1
-rw-r--r--ext/strscan/depend1
-rw-r--r--ext/win32/lib/win32/registry.rb30
-rw-r--r--ext/zlib/depend1
-rw-r--r--ext/zlib/zlib.c110
-rw-r--r--gc.c235
-rw-r--r--gems/bundled_gems6
-rw-r--r--hrtime.h14
-rw-r--r--imemo.c8
-rw-r--r--include/ruby/internal/encoding/encoding.h1
-rw-r--r--include/ruby/internal/memory.h6
-rw-r--r--include/ruby/internal/stdckdint.h68
-rw-r--r--include/ruby/io/buffer.h8
-rw-r--r--internal/encoding.h1
-rw-r--r--internal/gc.h3
-rw-r--r--internal/imemo.h2
-rw-r--r--internal/parse.h17
-rw-r--r--internal/ruby_parser.h23
-rw-r--r--io_buffer.c2
-rw-r--r--iseq.c114
-rw-r--r--lib/bundled_gems.rb9
-rw-r--r--lib/bundler.rb38
-rw-r--r--lib/bundler/cli.rb26
-rw-r--r--lib/bundler/cli/install.rb2
-rw-r--r--lib/bundler/constants.rb9
-rw-r--r--lib/bundler/definition.rb85
-rw-r--r--lib/bundler/environment_preserver.rb22
-rw-r--r--lib/bundler/errors.rb14
-rw-r--r--lib/bundler/installer.rb16
-rw-r--r--lib/bundler/man/bundle-add.12
-rw-r--r--lib/bundler/man/bundle-binstubs.12
-rw-r--r--lib/bundler/man/bundle-cache.12
-rw-r--r--lib/bundler/man/bundle-check.14
-rw-r--r--lib/bundler/man/bundle-check.1.ronn3
-rw-r--r--lib/bundler/man/bundle-clean.12
-rw-r--r--lib/bundler/man/bundle-config.14
-rw-r--r--lib/bundler/man/bundle-config.1.ronn3
-rw-r--r--lib/bundler/man/bundle-console.12
-rw-r--r--lib/bundler/man/bundle-doctor.12
-rw-r--r--lib/bundler/man/bundle-exec.12
-rw-r--r--lib/bundler/man/bundle-gem.12
-rw-r--r--lib/bundler/man/bundle-help.12
-rw-r--r--lib/bundler/man/bundle-info.12
-rw-r--r--lib/bundler/man/bundle-init.12
-rw-r--r--lib/bundler/man/bundle-inject.12
-rw-r--r--lib/bundler/man/bundle-install.12
-rw-r--r--lib/bundler/man/bundle-list.12
-rw-r--r--lib/bundler/man/bundle-lock.12
-rw-r--r--lib/bundler/man/bundle-open.12
-rw-r--r--lib/bundler/man/bundle-outdated.12
-rw-r--r--lib/bundler/man/bundle-platform.12
-rw-r--r--lib/bundler/man/bundle-plugin.12
-rw-r--r--lib/bundler/man/bundle-pristine.12
-rw-r--r--lib/bundler/man/bundle-remove.12
-rw-r--r--lib/bundler/man/bundle-show.12
-rw-r--r--lib/bundler/man/bundle-update.12
-rw-r--r--lib/bundler/man/bundle-version.12
-rw-r--r--lib/bundler/man/bundle-viz.12
-rw-r--r--lib/bundler/man/bundle.12
-rw-r--r--lib/bundler/man/gemfile.52
-rw-r--r--lib/bundler/plugin/events.rb24
-rw-r--r--lib/bundler/rubygems_ext.rb38
-rw-r--r--lib/bundler/rubygems_integration.rb12
-rw-r--r--lib/bundler/runtime.rb19
-rw-r--r--lib/bundler/settings.rb1
-rw-r--r--lib/bundler/setup.rb3
-rw-r--r--lib/bundler/shared_helpers.rb10
-rw-r--r--lib/bundler/source/metadata.rb2
-rw-r--r--lib/bundler/source/rubygems.rb19
-rw-r--r--lib/bundler/source_list.rb17
-rw-r--r--lib/bundler/spec_set.rb1
-rw-r--r--lib/did_you_mean/did_you_mean.gemspec2
-rw-r--r--lib/find.gemspec2
-rw-r--r--lib/ipaddr.rb6
-rw-r--r--lib/irb.rb98
-rw-r--r--lib/irb/color.rb4
-rw-r--r--lib/irb/command.rb8
-rw-r--r--lib/irb/command/base.rb4
-rw-r--r--lib/irb/command/chws.rb5
-rw-r--r--lib/irb/command/debug.rb17
-rw-r--r--lib/irb/command/exit.rb4
-rw-r--r--lib/irb/command/force_exit.rb4
-rw-r--r--lib/irb/command/help.rb30
-rw-r--r--lib/irb/command/subirb.rb5
-rw-r--r--lib/irb/completion.rb2
-rw-r--r--lib/irb/context.rb29
-rw-r--r--lib/irb/default_commands.rb207
-rw-r--r--lib/irb/helper_method.rb29
-rw-r--r--lib/irb/helper_method/base.rb16
-rw-r--r--lib/irb/helper_method/conf.rb11
-rw-r--r--lib/irb/init.rb35
-rw-r--r--lib/irb/input-method.rb1
-rw-r--r--lib/irb/ruby-lex.rb46
-rw-r--r--lib/irb/version.rb4
-rw-r--r--lib/irb/workspace.rb20
-rw-r--r--lib/optparse/optparse.gemspec3
-rw-r--r--lib/prism.rb7
-rw-r--r--lib/prism/desugar_compiler.rb8
-rw-r--r--lib/prism/ffi.rb10
-rw-r--r--lib/prism/lex_compat.rb19
-rw-r--r--lib/prism/node_ext.rb181
-rw-r--r--lib/prism/node_inspector.rb68
-rw-r--r--lib/prism/parse_result.rb167
-rw-r--r--lib/prism/parse_result/comments.rb9
-rw-r--r--lib/prism/parse_result/newlines.rb115
-rw-r--r--lib/prism/pattern.rb18
-rw-r--r--lib/prism/polyfill/byteindex.rb13
-rw-r--r--lib/prism/polyfill/string.rb12
-rw-r--r--lib/prism/polyfill/unpack1.rb14
-rw-r--r--lib/prism/prism.gemspec72
-rw-r--r--lib/prism/translation/parser.rb21
-rw-r--r--lib/prism/translation/parser/compiler.rb257
-rw-r--r--lib/prism/translation/ripper.rb172
-rw-r--r--lib/prism/translation/ruby_parser.rb125
-rw-r--r--lib/reline.rb33
-rw-r--r--lib/reline/ansi.rb55
-rw-r--r--lib/reline/config.rb74
-rw-r--r--lib/reline/key_actor/base.rb4
-rw-r--r--lib/reline/key_actor/emacs.rb4
-rw-r--r--lib/reline/key_actor/vi_insert.rb6
-rw-r--r--lib/reline/line_editor.rb201
-rw-r--r--lib/reline/unicode.rb78
-rw-r--r--lib/reline/version.rb2
-rw-r--r--lib/ruby_vm/rjit/insn_compiler.rb6
-rw-r--r--lib/rubygems.rb7
-rw-r--r--lib/rubygems/commands/pristine_command.rb15
-rw-r--r--lib/rubygems/commands/setup_command.rb2
-rw-r--r--lib/rubygems/commands/uninstall_command.rb2
-rw-r--r--lib/rubygems/commands/update_command.rb17
-rw-r--r--lib/rubygems/dependency.rb14
-rw-r--r--lib/rubygems/deprecate.rb156
-rw-r--r--lib/rubygems/ext/cargo_builder.rb17
-rw-r--r--lib/rubygems/gemcutter_utilities/webauthn_poller.rb4
-rw-r--r--lib/rubygems/installer.rb2
-rw-r--r--lib/rubygems/package.rb17
-rw-r--r--lib/rubygems/package/tar_header.rb24
-rw-r--r--lib/rubygems/platform.rb1
-rw-r--r--lib/rubygems/specification.rb152
-rw-r--r--lib/rubygems/specification_policy.rb4
-rw-r--r--lib/rubygems/specification_record.rb213
-rw-r--r--lib/rubygems/uninstaller.rb24
-rw-r--r--lib/syntax_suggest/clean_document.rb2
-rw-r--r--lib/time.rb2
-rw-r--r--load.c6
-rw-r--r--man/ruby.114
-rw-r--r--marshal.c15
-rw-r--r--mini_builtin.c10
-rw-r--r--misc/lldb_rb/utils.py451
-rw-r--r--missing/setproctitle.c45
-rw-r--r--node.c86
-rw-r--r--node.h4
-rw-r--r--numeric.c2
-rw-r--r--object.c9
-rw-r--r--parse.y810
-rw-r--r--prism/config.yml372
-rw-r--r--prism/extension.c25
-rw-r--r--prism/extension.h2
-rw-r--r--prism/options.c4
-rw-r--r--prism/options.h4
-rw-r--r--prism/parser.h10
-rw-r--r--prism/prism.c1371
-rw-r--r--prism/static_literals.c154
-rw-r--r--prism/static_literals.h14
-rw-r--r--prism/templates/ext/prism/api_node.c.erb21
-rw-r--r--prism/templates/lib/prism/dsl.rb.erb4
-rw-r--r--prism/templates/lib/prism/inspect_visitor.rb.erb132
-rw-r--r--prism/templates/lib/prism/node.rb.erb146
-rw-r--r--prism/templates/lib/prism/reflection.rb.erb38
-rw-r--r--prism/templates/lib/prism/serialize.rb.erb12
-rw-r--r--prism/templates/src/diagnostic.c.erb86
-rw-r--r--prism/templates/src/token_type.c.erb14
-rwxr-xr-xprism/templates/template.rb1
-rw-r--r--prism/util/pm_integer.c11
-rw-r--r--prism/util/pm_strpbrk.c38
-rw-r--r--prism/version.h4
-rw-r--r--prism_compile.c1556
-rw-r--r--prism_compile.h2
-rw-r--r--proc.c2
-rw-r--r--ractor.c9
-rw-r--r--re.c4
-rw-r--r--regexec.c15
-rw-r--r--ruby.c40
-rw-r--r--ruby_parser.c508
-rw-r--r--rubyparser.h34
-rw-r--r--shape.c6
-rw-r--r--spec/bundler/commands/cache_spec.rb60
-rw-r--r--spec/bundler/commands/help_spec.rb7
-rw-r--r--spec/bundler/commands/install_spec.rb52
-rw-r--r--spec/bundler/commands/lock_spec.rb122
-rw-r--r--spec/bundler/commands/update_spec.rb46
-rw-r--r--spec/bundler/install/deploy_spec.rb46
-rw-r--r--spec/bundler/lock/lockfile_spec.rb4
-rw-r--r--spec/bundler/plugins/hook_spec.rb99
-rw-r--r--spec/bundler/runtime/inline_spec.rb18
-rw-r--r--spec/bundler/runtime/setup_spec.rb27
-rw-r--r--spec/bundler/runtime/with_unbundled_env_spec.rb6
-rw-r--r--spec/bundler/support/builders.rb1
-rw-r--r--spec/prism.mspec43
-rw-r--r--spec/ruby/core/binding/irb_spec.rb2
-rw-r--r--spec/ruby/core/encoding/inspect_spec.rb20
-rw-r--r--spec/ruby/core/string/index_spec.rb11
-rw-r--r--spec/ruby/core/warning/element_reference_spec.rb4
-rw-r--r--spec/ruby/language/break_spec.rb2
-rw-r--r--spec/ruby/optional/capi/ext/io_spec.c8
-rw-r--r--string.c8
-rw-r--r--template/Makefile.in25
-rw-r--r--template/prelude.c.tmpl30
-rw-r--r--test/.excludes-prism/TestCall.rb3
-rw-r--r--test/.excludes-prism/TestCoverage.rb1
-rw-r--r--test/.excludes-prism/TestIRB/RubyLexTest.rb1
-rw-r--r--test/.excludes-prism/TestISeq.rb5
-rw-r--r--test/.excludes-prism/TestM17N.rb11
-rw-r--r--test/.excludes-prism/TestMixedUnicodeEscape.rb2
-rw-r--r--test/.excludes-prism/TestParse.rb30
-rw-r--r--test/.excludes-prism/TestPatternMatching.rb2
-rw-r--r--test/.excludes-prism/TestRegexp.rb8
-rw-r--r--test/.excludes-prism/TestRequire.rb2
-rw-r--r--test/.excludes-prism/TestRubyLiteral.rb7
-rw-r--r--test/.excludes-prism/TestRubyOptimization.rb1
-rw-r--r--test/.excludes-prism/TestRubyVM.rb1
-rw-r--r--test/.excludes-prism/TestSetTraceFunc.rb2
-rw-r--r--test/.excludes-prism/TestSyntax.rb37
-rw-r--r--test/.excludes-prism/TestUnicodeEscape.rb1
-rw-r--r--test/coverage/test_coverage.rb55
-rw-r--r--test/irb/command/test_custom_command.rb149
-rw-r--r--test/irb/command/test_force_exit.rb12
-rw-r--r--test/irb/command/test_help.rb9
-rw-r--r--test/irb/command/test_multi_irb_commands.rb50
-rw-r--r--test/irb/helper.rb6
-rw-r--r--test/irb/test_color.rb2
-rw-r--r--test/irb/test_command.rb84
-rw-r--r--test/irb/test_context.rb8
-rw-r--r--test/irb/test_debugger_integration.rb44
-rw-r--r--test/irb/test_helper_method.rb134
-rw-r--r--test/irb/test_init.rb92
-rw-r--r--test/irb/test_irb.rb111
-rw-r--r--test/net/http/test_https.rb1
-rw-r--r--test/objspace/test_objspace.rb2
-rw-r--r--test/objspace/test_ractor.rb24
-rw-r--r--test/openssl/test_cipher.rb16
-rw-r--r--test/openssl/test_digest.rb20
-rw-r--r--test/openssl/test_pair.rb9
-rw-r--r--test/openssl/test_pkcs7.rb21
-rw-r--r--test/openssl/test_ssl.rb24
-rw-r--r--test/openssl/test_ts.rb2
-rw-r--r--test/openssl/test_x509req.rb7
-rw-r--r--test/prism/errors_test.rb78
-rw-r--r--test/prism/format_errors_test.rb42
-rw-r--r--test/prism/index_write_test.rb68
-rw-r--r--test/prism/location_test.rb3
-rw-r--r--test/prism/newline_test.rb10
-rw-r--r--test/prism/redundant_return_test.rb73
-rw-r--r--test/prism/ruby_api_test.rb54
-rw-r--r--test/prism/snapshots/arrays.txt20
-rw-r--r--test/prism/snapshots/blocks.txt4
-rw-r--r--test/prism/snapshots/boolean_operators.txt4
-rw-r--r--test/prism/snapshots/constants.txt123
-rw-r--r--test/prism/snapshots/defined.txt4
-rw-r--r--test/prism/snapshots/heredocs_nested.txt4
-rw-r--r--test/prism/snapshots/if.txt3
-rw-r--r--test/prism/snapshots/method_calls.txt49
-rw-r--r--test/prism/snapshots/methods.txt3
-rw-r--r--test/prism/snapshots/modules.txt28
-rw-r--r--test/prism/snapshots/patterns.txt42
-rw-r--r--test/prism/snapshots/rescue.txt3
-rw-r--r--test/prism/snapshots/return.txt10
-rw-r--r--test/prism/snapshots/seattlerb/assoc_label.txt2
-rw-r--r--test/prism/snapshots/seattlerb/block_return.txt1
-rw-r--r--test/prism/snapshots/seattlerb/bug_249.txt2
-rw-r--r--test/prism/snapshots/seattlerb/bug_hash_args.txt2
-rw-r--r--test/prism/snapshots/seattlerb/bug_hash_args_trailing_comma.txt2
-rw-r--r--test/prism/snapshots/seattlerb/call_arg_assoc.txt2
-rw-r--r--test/prism/snapshots/seattlerb/call_arg_assoc_kwsplat.txt2
-rw-r--r--test/prism/snapshots/seattlerb/call_arg_kwsplat.txt2
-rw-r--r--test/prism/snapshots/seattlerb/call_args_assoc_quoted.txt6
-rw-r--r--test/prism/snapshots/seattlerb/call_args_assoc_trailing_comma.txt2
-rw-r--r--test/prism/snapshots/seattlerb/call_assoc.txt2
-rw-r--r--test/prism/snapshots/seattlerb/call_assoc_new.txt2
-rw-r--r--test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt2
-rw-r--r--test/prism/snapshots/seattlerb/call_assoc_trailing_comma.txt2
-rw-r--r--test/prism/snapshots/seattlerb/call_kwsplat.txt2
-rw-r--r--test/prism/snapshots/seattlerb/case_in_86.txt7
-rw-r--r--test/prism/snapshots/seattlerb/case_in_86_2.txt7
-rw-r--r--test/prism/snapshots/seattlerb/case_in_array_pat_const2.txt7
-rw-r--r--test/prism/snapshots/seattlerb/case_in_multiple.txt14
-rw-r--r--test/prism/snapshots/seattlerb/const_2_op_asgn_or2.txt14
-rw-r--r--test/prism/snapshots/seattlerb/const_3_op_asgn_or.txt7
-rw-r--r--test/prism/snapshots/seattlerb/const_op_asgn_and1.txt11
-rw-r--r--test/prism/snapshots/seattlerb/const_op_asgn_and2.txt7
-rw-r--r--test/prism/snapshots/seattlerb/const_op_asgn_or.txt7
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_env.txt2
-rw-r--r--test/prism/snapshots/seattlerb/difficult2_.txt2
-rw-r--r--test/prism/snapshots/seattlerb/dstr_evstr.txt2
-rw-r--r--test/prism/snapshots/seattlerb/dstr_str.txt4
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_nested.txt4
-rw-r--r--test/prism/snapshots/seattlerb/index_0_opasgn.txt4
-rw-r--r--test/prism/snapshots/seattlerb/masgn_colon2.txt7
-rw-r--r--test/prism/snapshots/seattlerb/masgn_colon3.txt14
-rw-r--r--test/prism/snapshots/seattlerb/messy_op_asgn_lineno.txt11
-rw-r--r--test/prism/snapshots/seattlerb/method_call_assoc_trailing_comma.txt2
-rw-r--r--test/prism/snapshots/seattlerb/multiline_hash_declaration.txt6
-rw-r--r--test/prism/snapshots/seattlerb/op_asgn_primary_colon_const_command_call.txt11
-rw-r--r--test/prism/snapshots/seattlerb/op_asgn_primary_colon_identifier1.txt4
-rw-r--r--test/prism/snapshots/seattlerb/op_asgn_primary_colon_identifier_command_call.txt4
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_defn_complex.txt5
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_op_asgn.txt4
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_return.txt1
-rw-r--r--test/prism/snapshots/seattlerb/parse_opt_call_args_assocs_comma.txt2
-rw-r--r--test/prism/snapshots/seattlerb/pct_w_heredoc_interp_nested.txt4
-rw-r--r--test/prism/snapshots/seattlerb/quoted_symbol_hash_arg.txt2
-rw-r--r--test/prism/snapshots/seattlerb/return_call_assocs.txt18
-rw-r--r--test/prism/snapshots/seattlerb/safe_op_asgn.txt4
-rw-r--r--test/prism/snapshots/seattlerb/str_str.txt4
-rw-r--r--test/prism/snapshots/seattlerb/str_str_str.txt4
-rw-r--r--test/prism/snapshots/unless.txt1
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/assignment.txt28
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/class.txt49
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/defs.txt14
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/dstr.txt1
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/literal.txt4
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/module.txt21
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/opasgn.txt64
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/rescue.txt2
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/send.txt12
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/since/32.txt2
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/variables.txt28
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/opasgn.txt4
-rw-r--r--test/prism/snapshots/until.txt1
-rw-r--r--test/prism/snapshots/while.txt1
-rw-r--r--test/prism/snapshots/whitequark/args_args_assocs.txt4
-rw-r--r--test/prism/snapshots/whitequark/args_args_assocs_comma.txt2
-rw-r--r--test/prism/snapshots/whitequark/args_assocs_comma.txt2
-rw-r--r--test/prism/snapshots/whitequark/bug_cmdarg.txt4
-rw-r--r--test/prism/snapshots/whitequark/casgn_scoped.txt7
-rw-r--r--test/prism/snapshots/whitequark/casgn_toplevel.txt7
-rw-r--r--test/prism/snapshots/whitequark/const_op_asgn.txt40
-rw-r--r--test/prism/snapshots/whitequark/const_scoped.txt7
-rw-r--r--test/prism/snapshots/whitequark/const_toplevel.txt7
-rw-r--r--test/prism/snapshots/whitequark/cpath.txt14
-rw-r--r--test/prism/snapshots/whitequark/dedenting_heredoc.txt4
-rw-r--r--test/prism/snapshots/whitequark/forwarded_argument_with_kwrestarg.txt2
-rw-r--r--test/prism/snapshots/whitequark/forwarded_kwrestarg.txt2
-rw-r--r--test/prism/snapshots/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt2
-rw-r--r--test/prism/snapshots/whitequark/keyword_argument_omission.txt2
-rw-r--r--test/prism/snapshots/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt2
-rw-r--r--test/prism/snapshots/whitequark/masgn_const.txt14
-rw-r--r--test/prism/snapshots/whitequark/newline_in_hash_argument.txt4
-rw-r--r--test/prism/snapshots/whitequark/op_asgn.txt12
-rw-r--r--test/prism/snapshots/whitequark/op_asgn_cmd.txt23
-rw-r--r--test/prism/snapshots/whitequark/op_asgn_index.txt4
-rw-r--r--test/prism/snapshots/whitequark/op_asgn_index_cmd.txt4
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_525.txt2
-rw-r--r--test/prism/snapshots/whitequark/rescue_mod_op_assign.txt4
-rw-r--r--test/prism/snapshots/whitequark/return.txt4
-rw-r--r--test/prism/snapshots/whitequark/return_block.txt1
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11380.txt2
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_12073.txt9
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_12402.txt54
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_12669.txt16
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_9669.txt1
-rw-r--r--test/prism/snapshots/whitequark/send_attr_asgn.txt7
-rw-r--r--test/prism/snapshots/whitequark/var_op_asgn.txt16
-rw-r--r--test/prism/snapshots/whitequark/var_op_asgn_cmd.txt4
-rw-r--r--test/prism/unescape_test.rb2
-rw-r--r--test/prism/warnings_test.rb10
-rw-r--r--test/reline/test_config.rb116
-rw-r--r--test/reline/test_key_actor_emacs.rb110
-rw-r--r--test/reline/test_line_editor.rb30
-rw-r--r--test/reline/test_reline.rb20
-rw-r--r--test/reline/test_unicode.rb31
-rw-r--r--test/reline/test_within_pipe.rb1
-rwxr-xr-xtest/reline/yamatanooroti/multiline_repl9
-rw-r--r--test/reline/yamatanooroti/test_rendering.rb110
-rw-r--r--test/ripper/test_parser_events.rb20
-rw-r--r--test/ripper/test_ripper.rb8
-rw-r--r--test/ruby/test_ast.rb32
-rw-r--r--test/ruby/test_iseq.rb23
-rw-r--r--test/ruby/test_m17n.rb4
-rw-r--r--test/ruby/test_marshal.rb10
-rw-r--r--test/ruby/test_parse.rb79
-rw-r--r--test/ruby/test_pattern_matching.rb2
-rw-r--r--test/ruby/test_regexp.rb8
-rw-r--r--test/ruby/test_rubyvm.rb9
-rw-r--r--test/ruby/test_symbol.rb1
-rw-r--r--test/ruby/test_syntax.rb32
-rw-r--r--test/ruby/test_yjit.rb2
-rw-r--r--test/rubygems/helper.rb42
-rw-r--r--test/rubygems/test_gem.rb6
-rw-r--r--test/rubygems/test_gem_ci_detector.rb14
-rw-r--r--test/rubygems/test_gem_commands_rebuild_command.rb13
-rw-r--r--test/rubygems/test_gem_commands_setup_command.rb23
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock8
-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.lock8
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml2
-rw-r--r--test/rubygems/test_gem_package_tar_header.rb25
-rw-r--r--test/rubygems/test_gem_platform.rb3
-rw-r--r--test/rubygems/test_gem_specification.rb27
-rw-r--r--test/rubygems/test_gem_uninstaller.rb95
-rw-r--r--test/rubygems/test_webauthn_poller.rb12
-rw-r--r--test/test_delegate.rb9
-rw-r--r--test/test_ipaddr.rb8
-rw-r--r--test/win32/test_registry.rb97
-rw-r--r--test/zlib/test_zlib.rb30
-rw-r--r--thread_pthread.c5
-rw-r--r--tool/bundler/dev_gems.rb2
-rw-r--r--tool/lib/_tmpdir.rb100
-rw-r--r--tool/lib/output.rb13
-rw-r--r--tool/lib/test/unit.rb30
-rw-r--r--tool/lib/test/unit/assertions.rb9
-rw-r--r--tool/lrama/lib/lrama/command.rb5
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb21
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb22
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rule/rule.rb6
-rw-r--r--tool/lrama/lib/lrama/grammar/rule.rb6
-rw-r--r--tool/lrama/lib/lrama/grammar/rule_builder.rb86
-rw-r--r--tool/lrama/lib/lrama/lexer.rb1
-rw-r--r--tool/lrama/lib/lrama/lexer/grammar_file.rb12
-rw-r--r--tool/lrama/lib/lrama/option_parser.rb5
-rw-r--r--tool/lrama/lib/lrama/parser.rb1062
-rw-r--r--tool/lrama/lib/lrama/state.rb28
-rw-r--r--tool/lrama/lib/lrama/version.rb2
-rwxr-xr-xtool/merger.rb9
-rwxr-xr-x[-rw-r--r--]tool/rdoc-srcdir0
-rw-r--r--tool/rubyspec_temp.rb13
-rw-r--r--tool/test/testunit/test_assertion.rb13
-rwxr-xr-xtool/test_for_warn_bundled_gems/test.sh4
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_bootsnap_rubyarchdir_gem.rb11
-rw-r--r--tool/update-NEWS-refs.rb7
-rw-r--r--universal_parser.c17
-rw-r--r--vm.c32
-rw-r--r--vm_callinfo.h18
-rw-r--r--vm_core.h17
-rw-r--r--vm_eval.c114
-rw-r--r--vm_insnhelper.c52
-rw-r--r--vm_insnhelper.h8
-rw-r--r--vm_method.c17
-rw-r--r--weakmap.c8
-rw-r--r--yjit.c17
-rw-r--r--yjit.h10
-rw-r--r--yjit.rb26
-rw-r--r--yjit/bindgen/src/main.rs4
-rw-r--r--yjit/src/asm/arm64/mod.rs63
-rw-r--r--yjit/src/backend/arm64/mod.rs74
-rw-r--r--yjit/src/backend/ir.rs17
-rw-r--r--yjit/src/backend/x86_64/mod.rs2
-rw-r--r--yjit/src/codegen.rs252
-rw-r--r--yjit/src/core.rs40
-rw-r--r--yjit/src/cruby.rs25
-rw-r--r--yjit/src/cruby_bindings.inc.rs13
-rw-r--r--yjit/src/invariants.rs101
-rw-r--r--yjit/src/stats.rs4
599 files changed, 12645 insertions, 6103 deletions
diff --git a/.github/actions/setup/directories/action.yml b/.github/actions/setup/directories/action.yml
index 63abd4ae58..5264e0e969 100644
--- a/.github/actions/setup/directories/action.yml
+++ b/.github/actions/setup/directories/action.yml
@@ -88,7 +88,7 @@ runs:
git config --global init.defaultBranch garbage
- if: inputs.checkout
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
path: ${{ inputs.srcdir }}
fetch-depth: ${{ inputs.fetch-depth }}
diff --git a/.github/workflows/annocheck.yml b/.github/workflows/annocheck.yml
index f3f496c29a..6c03f52289 100644
--- a/.github/workflows/annocheck.yml
+++ b/.github/workflows/annocheck.yml
@@ -4,7 +4,7 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -12,7 +12,7 @@ on:
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -63,7 +63,7 @@ jobs:
- run: id
working-directory:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
@@ -74,7 +74,7 @@ jobs:
builddir: build
makeup: true
- - uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
+ - uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
with:
ruby-version: '3.0'
bundler: none
diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml
index 50ff7014ff..ce979c9e7a 100644
--- a/.github/workflows/baseruby.yml
+++ b/.github/workflows/baseruby.yml
@@ -4,7 +4,7 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -12,7 +12,7 @@ on:
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -51,12 +51,12 @@ jobs:
- ruby-3.3
steps:
- - uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
+ - uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
with:
ruby-version: ${{ matrix.ruby }}
bundler: none
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: ./.github/actions/setup/ubuntu
diff --git a/.github/workflows/bundled_gems.yml b/.github/workflows/bundled_gems.yml
index 96bca3e3aa..6f06451a99 100644
--- a/.github/workflows/bundled_gems.yml
+++ b/.github/workflows/bundled_gems.yml
@@ -31,7 +31,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml
index a5e491d7a4..8ecae4f223 100644
--- a/.github/workflows/check_dependencies.yml
+++ b/.github/workflows/check_dependencies.yml
@@ -3,7 +3,7 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -11,7 +11,7 @@ on:
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -45,7 +45,7 @@ jobs:
)}}
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: ./.github/actions/setup/ubuntu
if: ${{ contains(matrix.os, 'ubuntu') }}
@@ -55,7 +55,7 @@ jobs:
- uses: ./.github/actions/setup/directories
- - uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
+ - uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
with:
ruby-version: '3.0'
bundler: none
diff --git a/.github/workflows/check_misc.yml b/.github/workflows/check_misc.yml
index 7996ddb4c0..f26319f448 100644
--- a/.github/workflows/check_misc.yml
+++ b/.github/workflows/check_misc.yml
@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index f0dab96550..d6a2e297be 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -5,7 +5,7 @@ on:
branches: ['master']
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -13,7 +13,7 @@ on:
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -63,7 +63,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- name: Install libraries
if: ${{ contains(matrix.os, 'macos') }}
@@ -80,15 +80,15 @@ jobs:
run: sudo rm /usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb
- name: Initialize CodeQL
- uses: github/codeql-action/init@df5a14dc28094dc936e103b37d749c6628682b60 # v3.25.0
+ uses: github/codeql-action/init@b7cec7526559c32f1616476ff32d17ba4c59b2d6 # v3.25.5
with:
languages: ${{ matrix.language }}
- name: Autobuild
- uses: github/codeql-action/autobuild@df5a14dc28094dc936e103b37d749c6628682b60 # v3.25.0
+ uses: github/codeql-action/autobuild@b7cec7526559c32f1616476ff32d17ba4c59b2d6 # v3.25.5
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@df5a14dc28094dc936e103b37d749c6628682b60 # v3.25.0
+ uses: github/codeql-action/analyze@b7cec7526559c32f1616476ff32d17ba4c59b2d6 # v3.25.5
with:
category: '/language:${{ matrix.language }}'
upload: False
@@ -118,7 +118,7 @@ jobs:
continue-on-error: true
- name: Upload SARIF
- uses: github/codeql-action/upload-sarif@df5a14dc28094dc936e103b37d749c6628682b60 # v3.25.0
+ uses: github/codeql-action/upload-sarif@b7cec7526559c32f1616476ff32d17ba4c59b2d6 # v3.25.5
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 0eebb0eea2..8937a5b15f 100644
--- a/.github/workflows/compilers.yml
+++ b/.github/workflows/compilers.yml
@@ -4,7 +4,7 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -12,7 +12,7 @@ on:
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -147,9 +147,9 @@ jobs:
- { name: disable-rubygems, env: { append_configure: '--disable-rubygems' } }
- { name: RUBY_DEVEL, env: { append_configure: '--enable-devel' } }
+ - { name: OPT_THREADED_CODE=0, env: { cppflags: '-DOPT_THREADED_CODE=0' } }
- { name: OPT_THREADED_CODE=1, env: { cppflags: '-DOPT_THREADED_CODE=1' } }
- { name: OPT_THREADED_CODE=2, env: { cppflags: '-DOPT_THREADED_CODE=2' } }
- - { name: OPT_THREADED_CODE=3, env: { cppflags: '-DOPT_THREADED_CODE=3' } }
- { name: NDEBUG, env: { cppflags: '-DNDEBUG' } }
- { name: RUBY_DEBUG, env: { cppflags: '-DRUBY_DEBUG' } }
@@ -233,7 +233,7 @@ jobs:
- run: id
working-directory:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
diff --git a/.github/workflows/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml
index fa50511eb2..80112a0af3 100644
--- a/.github/workflows/dependabot_automerge.yml
+++ b/.github/workflows/dependabot_automerge.yml
@@ -11,7 +11,7 @@ jobs:
steps:
- name: Dependabot metadata
- uses: dependabot/fetch-metadata@0fb21704c18a42ce5aa8d720ea4b912f5e6babef # v2.0.0
+ uses: dependabot/fetch-metadata@5e5f99653a5b510e8555840e80cbf1514ad4af38 # v2.1.0
id: metadata
- name: Wait for status checks
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index 87231228bc..e71706b186 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -3,7 +3,7 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -52,7 +52,7 @@ jobs:
)}}
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml
index d8c075fc7a..4170369def 100644
--- a/.github/workflows/mingw.yml
+++ b/.github/workflows/mingw.yml
@@ -3,7 +3,7 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -11,7 +11,7 @@ on:
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -66,7 +66,7 @@ jobs:
steps:
- name: Set up Ruby & MSYS2
- uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
+ uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
with:
ruby-version: ${{ matrix.baseruby }}
@@ -97,7 +97,7 @@ jobs:
$result
working-directory:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
diff --git a/.github/workflows/prism.yml b/.github/workflows/prism.yml
index adb9206c36..78b6469db1 100644
--- a/.github/workflows/prism.yml
+++ b/.github/workflows/prism.yml
@@ -55,7 +55,7 @@ jobs:
)}}
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
@@ -92,7 +92,7 @@ jobs:
timeout-minutes: 40
env:
GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: '-q --tty=no --excludes-dir="../src/test/.excludes-prism" --exclude="test_ast.rb" --exclude="error_highlight/test_error_highlight.rb" --exclude="prism/encoding_test.rb" --exclude="prism/locals_test.rb" --exclude="prism/newline_test.rb"'
+ RUBY_TESTOPTS: '-q --tty=no --excludes-dir="../src/test/.excludes-prism" --exclude="error_highlight/test_error_highlight.rb" --exclude="prism/encoding_test.rb"'
RUN_OPTS: ${{ matrix.run_opts }}
- name: make test-prism-spec
diff --git a/.github/workflows/rjit-bindgen.yml b/.github/workflows/rjit-bindgen.yml
index b77d79e83a..c4cfe9ed83 100644
--- a/.github/workflows/rjit-bindgen.yml
+++ b/.github/workflows/rjit-bindgen.yml
@@ -3,7 +3,7 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -11,7 +11,7 @@ on:
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -47,11 +47,11 @@ jobs:
steps:
- name: Set up Ruby
- uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
+ uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
with:
ruby-version: '3.1'
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
diff --git a/.github/workflows/rjit.yml b/.github/workflows/rjit.yml
index b393074919..509088db7d 100644
--- a/.github/workflows/rjit.yml
+++ b/.github/workflows/rjit.yml
@@ -55,7 +55,7 @@ jobs:
)}}
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index 99f85235ad..85ee3e2a48 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -32,12 +32,12 @@ jobs:
steps:
- name: 'Checkout code'
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
persist-credentials: false
- name: 'Run analysis'
- uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
+ uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
with:
results_file: results.sarif
results_format: sarif
@@ -67,6 +67,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: 'Upload to code-scanning'
- uses: github/codeql-action/upload-sarif@df5a14dc28094dc936e103b37d749c6628682b60 # v2.1.27
+ uses: github/codeql-action/upload-sarif@b7cec7526559c32f1616476ff32d17ba4c59b2d6 # v2.1.27
with:
sarif_file: results.sarif
diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml
index bb4bf8441f..14669a13b3 100644
--- a/.github/workflows/spec_guards.yml
+++ b/.github/workflows/spec_guards.yml
@@ -45,9 +45,9 @@ jobs:
- ruby-3.3
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- - uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
+ - uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
with:
ruby-version: ${{ matrix.ruby }}
bundler: none
diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index 8f70fcfaaf..697056df60 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -3,7 +3,7 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -58,7 +58,7 @@ jobs:
)}}
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
@@ -67,7 +67,7 @@ jobs:
with:
arch: ${{ matrix.arch }}
- - uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
+ - uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
with:
ruby-version: '3.0'
bundler: none
diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml
index 1e0a0574be..764ca2d21c 100644
--- a/.github/workflows/wasm.yml
+++ b/.github/workflows/wasm.yml
@@ -3,7 +3,7 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -11,7 +11,7 @@ on:
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -61,7 +61,7 @@ jobs:
)}}
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
@@ -100,7 +100,7 @@ jobs:
run: |
echo "WASI_SDK_PATH=/opt/wasi-sdk" >> $GITHUB_ENV
- - uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
+ - uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
with:
ruby-version: '3.0'
bundler: none
@@ -136,7 +136,7 @@ jobs:
- run: tar cfz ../install.tar.gz -C ../install .
- name: Upload artifacts
- uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
+ uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: ruby-wasm-install
path: ${{ github.workspace }}/install.tar.gz
@@ -164,7 +164,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@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
+ - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
if: ${{ github.event_name == 'pull_request' }}
with:
name: github-pr-info
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index e1a1829755..fcf600263b 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -3,7 +3,7 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -11,7 +11,7 @@ on:
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -91,7 +91,7 @@ jobs:
${{ steps.find-tools.outputs.needs }}
if: ${{ steps.find-tools.outputs.needs != '' }}
- - uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
+ - uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
with:
ruby-version: '3.0'
bundler: none
@@ -123,7 +123,7 @@ jobs:
Join-Path (Resolve-Path ~).Path "scoop\shims" >> $Env:GITHUB_PATH
shell: pwsh
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
diff --git a/.github/workflows/yjit-macos.yml b/.github/workflows/yjit-macos.yml
index 5e209cc4ca..bd17b302ae 100644
--- a/.github/workflows/yjit-macos.yml
+++ b/.github/workflows/yjit-macos.yml
@@ -3,7 +3,7 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -37,7 +37,7 @@ jobs:
)}}
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- run: RUST_BACKTRACE=1 cargo test
working-directory: yjit
@@ -60,11 +60,13 @@ jobs:
- test_task: 'check'
configure: '--enable-yjit=dev'
yjit_opts: '--yjit-call-threshold=1 --yjit-verify-ctx --yjit-code-gc'
+ specopts: '-T --yjit-call-threshold=1 -T --yjit-verify-ctx -T --yjit-code-gc'
fail-fast: false
env:
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
RUN_OPTS: ${{ matrix.yjit_opts }}
+ SPECOPTS: ${{ matrix.specopts }}
runs-on: ${{ github.repository == 'ruby/ruby' && 'macos-arm-oss' || 'macos-14' }}
@@ -79,7 +81,7 @@ jobs:
)}}
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
@@ -128,6 +130,7 @@ jobs:
run: >-
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
RUN_OPTS="$RUN_OPTS"
+ SPECOPTS="$SPECOPTS"
timeout-minutes: 60
env:
RUBY_TESTOPTS: '-q --tty=no'
diff --git a/.github/workflows/yjit-ubuntu.yml b/.github/workflows/yjit-ubuntu.yml
index dcf7e1874a..bd7e25a9cd 100644
--- a/.github/workflows/yjit-ubuntu.yml
+++ b/.github/workflows/yjit-ubuntu.yml
@@ -3,7 +3,7 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man'
+ - '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
@@ -36,7 +36,7 @@ jobs:
)}}
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
# For now we can't run cargo test --offline because it complains about the
# capstone dependency, even though the dependency is optional
@@ -68,7 +68,7 @@ jobs:
)}}
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
# Check that we don't have linting errors in release mode, too
- run: cargo clippy --all-targets --all-features
@@ -95,6 +95,7 @@ jobs:
- test_task: 'check'
configure: '--enable-yjit=dev'
yjit_opts: '--yjit-call-threshold=1 --yjit-verify-ctx --yjit-code-gc'
+ specopts: '-T --yjit-call-threshold=1 -T --yjit-verify-ctx -T --yjit-code-gc'
- test_task: 'test-bundled-gems'
configure: '--enable-yjit=dev'
@@ -108,6 +109,7 @@ jobs:
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
@@ -125,7 +127,7 @@ jobs:
)}}
steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
@@ -145,7 +147,7 @@ jobs:
if: ${{ matrix.rust_version }}
run: rustup install ${{ matrix.rust_version }} --profile minimal
- - uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
+ - uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
with:
ruby-version: '3.0'
bundler: none
@@ -179,10 +181,10 @@ jobs:
- name: make ${{ matrix.test_task }}
run: >-
- make -s -j ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
- RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug
+ 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: 60
+ timeout-minutes: 90
env:
RUBY_TESTOPTS: '-q --tty=no'
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
diff --git a/.gitignore b/.gitignore
index de4b972193..b6beba3b3e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -167,6 +167,7 @@ lcov*.info
# /coroutine/
!/coroutine/**/*.s
+!/coroutine/**/*.S
# /enc/trans/
/enc/trans/*.c
@@ -261,8 +262,10 @@ lcov*.info
/lib/prism/dispatcher.rb
/lib/prism/dot_visitor.rb
/lib/prism/dsl.rb
+/lib/prism/inspect_visitor.rb
/lib/prism/mutation_compiler.rb
/lib/prism/node.rb
+/lib/prism/reflection.rb
/lib/prism/serialize.rb
/lib/prism/visitor.rb
/prism/api_node.c
diff --git a/NEWS.md b/NEWS.md
index f3368421a9..5972eac924 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -45,24 +45,25 @@ The following default gems are updated.
* erb 4.0.4
* fiddle 1.1.3
* io-console 0.7.2
-* irb 1.12.0
+* irb 1.13.1
* json 2.7.2
* net-http 0.4.1
* optparse 0.5.0
-* prism 0.25.0
+* prism 0.29.0
* rdoc 6.6.3.1
-* reline 0.5.2
+* reline 0.5.7
* resolv 0.4.0
* stringio 3.1.1
* strscan 3.1.1
The following bundled gems are updated.
-* minitest 5.22.3
+* minitest 5.23.0
* rake 13.2.1
* test-unit 3.6.2
+* rexml 3.2.8
* net-ftp 0.3.4
-* net-imap 0.4.10
+* net-imap 0.4.11
* net-smtp 0.5.0
* rbs 3.4.4
* typeprof 0.21.11
@@ -73,7 +74,7 @@ The following bundled gems are promoted from default gems.
* mutex_m 0.2.0
* getoptlong 0.2.1
* base64 0.2.0
-* bigdecimal 3.1.7
+* bigdecimal 3.1.8
* observer 0.1.2
* abbrev 0.1.2
* resolv-replace 0.1.1
@@ -90,8 +91,8 @@ See GitHub releases like [GitHub Releases of Logger](https://github.com/ruby/log
## Compatibility issues
* Error messages and backtrace displays have been changed.
- * Use a single quote instead of a backtick as a opening quote. [Feature #16495]
- * Display a class name before a method name (only when the class has a permanent name). [Feature #19117]
+ * Use a single quote instead of a backtick as a opening quote. [[Feature #16495]]
+ * Display a class name before a method name (only when the class has a permanent name). [[Feature #19117]]
* `Kernel#caller`, `Thread::Backtrace::Location`'s methods, etc. are also changed accordingly.
```
Old:
@@ -140,3 +141,4 @@ See GitHub releases like [GitHub Releases of Logger](https://github.com/ruby/log
[Feature #20205]: https://bugs.ruby-lang.org/issues/20205
[Bug #20218]: https://bugs.ruby-lang.org/issues/20218
[Feature #20265]: https://bugs.ruby-lang.org/issues/20265
+[Feature #20429]: https://bugs.ruby-lang.org/issues/20429
diff --git a/array.c b/array.c
index 56f3584e1d..6ad69dd23f 100644
--- a/array.c
+++ b/array.c
@@ -350,7 +350,7 @@ ary_memcpy(VALUE ary, long beg, long argc, const VALUE *argv)
}
static VALUE *
-ary_heap_alloc(size_t capa)
+ary_heap_alloc_buffer(size_t capa)
{
return ALLOC_N(VALUE, capa);
}
@@ -404,7 +404,7 @@ ary_resize_capa(VALUE ary, long capacity)
size_t new_capa = capacity;
if (ARY_EMBED_P(ary)) {
long len = ARY_EMBED_LEN(ary);
- VALUE *ptr = ary_heap_alloc(capacity);
+ VALUE *ptr = ary_heap_alloc_buffer(capacity);
MEMCPY(ptr, ARY_EMBED_PTR(ary), VALUE, len);
FL_UNSET_EMBED(ary);
@@ -555,7 +555,7 @@ rb_ary_cancel_sharing(VALUE ary)
rb_ary_decrement_share(shared_root);
}
else {
- VALUE *ptr = ary_heap_alloc(len);
+ VALUE *ptr = ary_heap_alloc_buffer(len);
MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len);
rb_ary_unshare(ary);
ARY_SET_CAPA(ary, len);
@@ -714,7 +714,7 @@ ary_new(VALUE klass, long capa)
ARY_SET_CAPA(ary, capa);
RUBY_ASSERT(!ARY_EMBED_P(ary));
- ARY_SET_PTR(ary, ary_heap_alloc(capa));
+ ARY_SET_PTR(ary, ary_heap_alloc_buffer(capa));
ARY_SET_HEAP_LEN(ary, 0);
}
@@ -818,7 +818,7 @@ ec_ary_new(rb_execution_context_t *ec, VALUE klass, long capa)
ARY_SET_CAPA(ary, capa);
RUBY_ASSERT(!ARY_EMBED_P(ary));
- ARY_SET_PTR(ary, ary_heap_alloc(capa));
+ ARY_SET_PTR(ary, ary_heap_alloc_buffer(capa));
ARY_SET_HEAP_LEN(ary, 0);
}
@@ -918,7 +918,7 @@ ary_make_shared(VALUE ary)
FL_SET_SHARED_ROOT(shared);
if (ARY_EMBED_P(ary)) {
- VALUE *ptr = ary_heap_alloc(capa);
+ VALUE *ptr = ary_heap_alloc_buffer(capa);
ARY_SET_PTR(shared, ptr);
ary_memcpy(shared, 0, len, RARRAY_CONST_PTR(ary));
@@ -4559,7 +4559,7 @@ rb_ary_replace(VALUE copy, VALUE orig)
* contents of orig. */
else if (ARY_EMBED_P(orig)) {
long len = ARY_EMBED_LEN(orig);
- VALUE *ptr = ary_heap_alloc(len);
+ VALUE *ptr = ary_heap_alloc_buffer(len);
FL_UNSET_EMBED(copy);
ARY_SET_PTR(copy, ptr);
diff --git a/ast.c b/ast.c
index a4c57b898b..12b3996f94 100644
--- a/ast.c
+++ b/ast.c
@@ -16,7 +16,7 @@ static VALUE rb_mAST;
static VALUE rb_cNode;
struct ASTNodeData {
- rb_ast_t *ast;
+ VALUE ast_value;
const NODE *node;
};
@@ -24,14 +24,16 @@ static void
node_gc_mark(void *ptr)
{
struct ASTNodeData *data = (struct ASTNodeData *)ptr;
- rb_gc_mark((VALUE)data->ast);
+ rb_gc_mark(data->ast_value);
}
static size_t
node_memsize(const void *ptr)
{
struct ASTNodeData *data = (struct ASTNodeData *)ptr;
- return rb_ast_memsize(data->ast);
+ rb_ast_t *ast = rb_ruby_ast_data_get(data->ast_value);
+
+ return sizeof(struct ASTNodeData) + rb_ast_memsize(ast);
}
static const rb_data_type_t rb_node_type = {
@@ -44,22 +46,22 @@ static const rb_data_type_t rb_node_type = {
static VALUE rb_ast_node_alloc(VALUE klass);
static void
-setup_node(VALUE obj, rb_ast_t *ast, const NODE *node)
+setup_node(VALUE obj, VALUE ast_value, const NODE *node)
{
struct ASTNodeData *data;
TypedData_Get_Struct(obj, struct ASTNodeData, &rb_node_type, data);
- data->ast = ast;
+ data->ast_value = ast_value;
data->node = node;
}
static VALUE
-ast_new_internal(rb_ast_t *ast, const NODE *node)
+ast_new_internal(VALUE ast_value, const NODE *node)
{
VALUE obj;
obj = rb_ast_node_alloc(rb_cNode);
- setup_node(obj, ast, node);
+ setup_node(obj, ast_value, node);
return obj;
}
@@ -74,14 +76,16 @@ ast_parse_new(void)
}
static VALUE
-ast_parse_done(rb_ast_t *ast)
+ast_parse_done(VALUE ast_value)
{
+ rb_ast_t *ast = rb_ruby_ast_data_get(ast_value);
+
if (!ast->body.root) {
rb_ast_dispose(ast);
rb_exc_raise(GET_EC()->errinfo);
}
- return ast_new_internal(ast, (NODE *)ast->body.root);
+ return ast_new_internal(ast_value, (NODE *)ast->body.root);
}
static VALUE
@@ -93,15 +97,15 @@ ast_s_parse(rb_execution_context_t *ec, VALUE module, VALUE str, VALUE keep_scri
static VALUE
rb_ast_parse_str(VALUE str, VALUE keep_script_lines, VALUE error_tolerant, VALUE keep_tokens)
{
- rb_ast_t *ast = 0;
+ VALUE ast_value;
StringValue(str);
VALUE vparser = ast_parse_new();
if (RTEST(keep_script_lines)) rb_parser_set_script_lines(vparser);
if (RTEST(error_tolerant)) rb_parser_error_tolerant(vparser);
if (RTEST(keep_tokens)) rb_parser_keep_tokens(vparser);
- ast = rb_parser_compile_string_path(vparser, Qnil, str, 1);
- return ast_parse_done(ast);
+ ast_value = rb_parser_compile_string_path(vparser, Qnil, str, 1);
+ return ast_parse_done(ast_value);
}
static VALUE
@@ -114,7 +118,7 @@ static VALUE
rb_ast_parse_file(VALUE path, VALUE keep_script_lines, VALUE error_tolerant, VALUE keep_tokens)
{
VALUE f;
- rb_ast_t *ast = 0;
+ VALUE ast_value = Qnil;
rb_encoding *enc = rb_utf8_encoding();
f = rb_file_open_str(path, "r");
@@ -123,39 +127,26 @@ rb_ast_parse_file(VALUE path, VALUE keep_script_lines, VALUE error_tolerant, VAL
if (RTEST(keep_script_lines)) rb_parser_set_script_lines(vparser);
if (RTEST(error_tolerant)) rb_parser_error_tolerant(vparser);
if (RTEST(keep_tokens)) rb_parser_keep_tokens(vparser);
- ast = rb_parser_compile_file_path(vparser, Qnil, f, 1);
+ ast_value = rb_parser_compile_file_path(vparser, Qnil, f, 1);
rb_io_close(f);
- return ast_parse_done(ast);
-}
-
-static VALUE
-lex_array(VALUE array, int index)
-{
- VALUE str = rb_ary_entry(array, index);
- if (!NIL_P(str)) {
- StringValue(str);
- if (!rb_enc_asciicompat(rb_enc_get(str))) {
- rb_raise(rb_eArgError, "invalid source encoding");
- }
- }
- return str;
+ return ast_parse_done(ast_value);
}
static VALUE
rb_ast_parse_array(VALUE array, VALUE keep_script_lines, VALUE error_tolerant, VALUE keep_tokens)
{
- rb_ast_t *ast = 0;
+ VALUE ast_value = Qnil;
array = rb_check_array_type(array);
VALUE vparser = ast_parse_new();
if (RTEST(keep_script_lines)) rb_parser_set_script_lines(vparser);
if (RTEST(error_tolerant)) rb_parser_error_tolerant(vparser);
if (RTEST(keep_tokens)) rb_parser_keep_tokens(vparser);
- ast = rb_parser_compile_generic(vparser, lex_array, Qnil, array, 1);
- return ast_parse_done(ast);
+ ast_value = rb_parser_compile_array(vparser, Qnil, array, 1);
+ return ast_parse_done(ast_value);
}
-static VALUE node_children(rb_ast_t*, const NODE*);
+static VALUE node_children(VALUE, const NODE*);
static VALUE
node_find(VALUE self, const int node_id)
@@ -167,7 +158,7 @@ node_find(VALUE self, const int node_id)
if (nd_node_id(data->node) == node_id) return self;
- ary = node_children(data->ast, data->node);
+ ary = node_children(data->ast_value, data->node);
for (i = 0; i < RARRAY_LEN(ary); i++) {
VALUE child = RARRAY_AREF(ary, i);
@@ -290,10 +281,10 @@ ast_node_node_id(rb_execution_context_t *ec, VALUE self)
return INT2FIX(nd_node_id(data->node));
}
-#define NEW_CHILD(ast, node) node ? ast_new_internal(ast, node) : Qnil
+#define NEW_CHILD(ast_value, node) (node ? ast_new_internal(ast_value, node) : Qnil)
static VALUE
-rb_ary_new_from_node_args(rb_ast_t *ast, long n, ...)
+rb_ary_new_from_node_args(VALUE ast_value, long n, ...)
{
va_list ar;
VALUE ary;
@@ -305,39 +296,39 @@ rb_ary_new_from_node_args(rb_ast_t *ast, long n, ...)
for (i=0; i<n; i++) {
NODE *node;
node = va_arg(ar, NODE *);
- rb_ary_push(ary, NEW_CHILD(ast, node));
+ rb_ary_push(ary, NEW_CHILD(ast_value, node));
}
va_end(ar);
return ary;
}
static VALUE
-dump_block(rb_ast_t *ast, const struct RNode_BLOCK *node)
+dump_block(VALUE ast_value, const struct RNode_BLOCK *node)
{
VALUE ary = rb_ary_new();
do {
- rb_ary_push(ary, NEW_CHILD(ast, node->nd_head));
+ rb_ary_push(ary, NEW_CHILD(ast_value, node->nd_head));
} while (node->nd_next &&
nd_type_p(node->nd_next, NODE_BLOCK) &&
(node = RNODE_BLOCK(node->nd_next), 1));
if (node->nd_next) {
- rb_ary_push(ary, NEW_CHILD(ast, node->nd_next));
+ rb_ary_push(ary, NEW_CHILD(ast_value, node->nd_next));
}
return ary;
}
static VALUE
-dump_array(rb_ast_t *ast, const struct RNode_LIST *node)
+dump_array(VALUE ast_value, const struct RNode_LIST *node)
{
VALUE ary = rb_ary_new();
- rb_ary_push(ary, NEW_CHILD(ast, node->nd_head));
+ rb_ary_push(ary, NEW_CHILD(ast_value, node->nd_head));
while (node->nd_next && nd_type_p(node->nd_next, NODE_LIST)) {
node = RNODE_LIST(node->nd_next);
- rb_ary_push(ary, NEW_CHILD(ast, node->nd_head));
+ rb_ary_push(ary, NEW_CHILD(ast_value, node->nd_head));
}
- rb_ary_push(ary, NEW_CHILD(ast, node->nd_next));
+ rb_ary_push(ary, NEW_CHILD(ast_value, node->nd_next));
return ary;
}
@@ -359,155 +350,155 @@ no_name_rest(void)
}
static VALUE
-rest_arg(rb_ast_t *ast, const NODE *rest_arg)
+rest_arg(VALUE ast_value, const NODE *rest_arg)
{
- return NODE_NAMED_REST_P(rest_arg) ? NEW_CHILD(ast, rest_arg) : no_name_rest();
+ return NODE_NAMED_REST_P(rest_arg) ? NEW_CHILD(ast_value, rest_arg) : no_name_rest();
}
static VALUE
-node_children(rb_ast_t *ast, const NODE *node)
+node_children(VALUE ast_value, const NODE *node)
{
char name[sizeof("$") + DECIMAL_SIZE_OF(long)];
enum node_type type = nd_type(node);
switch (type) {
case NODE_BLOCK:
- return dump_block(ast, RNODE_BLOCK(node));
+ return dump_block(ast_value, RNODE_BLOCK(node));
case NODE_IF:
- return rb_ary_new_from_node_args(ast, 3, RNODE_IF(node)->nd_cond, RNODE_IF(node)->nd_body, RNODE_IF(node)->nd_else);
+ return rb_ary_new_from_node_args(ast_value, 3, RNODE_IF(node)->nd_cond, RNODE_IF(node)->nd_body, RNODE_IF(node)->nd_else);
case NODE_UNLESS:
- return rb_ary_new_from_node_args(ast, 3, RNODE_UNLESS(node)->nd_cond, RNODE_UNLESS(node)->nd_body, RNODE_UNLESS(node)->nd_else);
+ return rb_ary_new_from_node_args(ast_value, 3, RNODE_UNLESS(node)->nd_cond, RNODE_UNLESS(node)->nd_body, RNODE_UNLESS(node)->nd_else);
case NODE_CASE:
- return rb_ary_new_from_node_args(ast, 2, RNODE_CASE(node)->nd_head, RNODE_CASE(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_CASE(node)->nd_head, RNODE_CASE(node)->nd_body);
case NODE_CASE2:
- return rb_ary_new_from_node_args(ast, 2, RNODE_CASE2(node)->nd_head, RNODE_CASE2(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_CASE2(node)->nd_head, RNODE_CASE2(node)->nd_body);
case NODE_CASE3:
- return rb_ary_new_from_node_args(ast, 2, RNODE_CASE3(node)->nd_head, RNODE_CASE3(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_CASE3(node)->nd_head, RNODE_CASE3(node)->nd_body);
case NODE_WHEN:
- return rb_ary_new_from_node_args(ast, 3, RNODE_WHEN(node)->nd_head, RNODE_WHEN(node)->nd_body, RNODE_WHEN(node)->nd_next);
+ return rb_ary_new_from_node_args(ast_value, 3, RNODE_WHEN(node)->nd_head, RNODE_WHEN(node)->nd_body, RNODE_WHEN(node)->nd_next);
case NODE_IN:
- return rb_ary_new_from_node_args(ast, 3, RNODE_IN(node)->nd_head, RNODE_IN(node)->nd_body, RNODE_IN(node)->nd_next);
+ return rb_ary_new_from_node_args(ast_value, 3, RNODE_IN(node)->nd_head, RNODE_IN(node)->nd_body, RNODE_IN(node)->nd_next);
case NODE_WHILE:
case NODE_UNTIL:
- return rb_ary_push(rb_ary_new_from_node_args(ast, 2, RNODE_WHILE(node)->nd_cond, RNODE_WHILE(node)->nd_body),
+ return rb_ary_push(rb_ary_new_from_node_args(ast_value, 2, RNODE_WHILE(node)->nd_cond, RNODE_WHILE(node)->nd_body),
RBOOL(RNODE_WHILE(node)->nd_state));
case NODE_ITER:
case NODE_FOR:
- return rb_ary_new_from_node_args(ast, 2, RNODE_ITER(node)->nd_iter, RNODE_ITER(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_ITER(node)->nd_iter, RNODE_ITER(node)->nd_body);
case NODE_FOR_MASGN:
- return rb_ary_new_from_node_args(ast, 1, RNODE_FOR_MASGN(node)->nd_var);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_FOR_MASGN(node)->nd_var);
case NODE_BREAK:
- return rb_ary_new_from_node_args(ast, 1, RNODE_BREAK(node)->nd_stts);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_BREAK(node)->nd_stts);
case NODE_NEXT:
- return rb_ary_new_from_node_args(ast, 1, RNODE_NEXT(node)->nd_stts);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_NEXT(node)->nd_stts);
case NODE_RETURN:
- return rb_ary_new_from_node_args(ast, 1, RNODE_RETURN(node)->nd_stts);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_RETURN(node)->nd_stts);
case NODE_REDO:
- return rb_ary_new_from_node_args(ast, 0);
+ return rb_ary_new_from_node_args(ast_value, 0);
case NODE_RETRY:
- return rb_ary_new_from_node_args(ast, 0);
+ return rb_ary_new_from_node_args(ast_value, 0);
case NODE_BEGIN:
- return rb_ary_new_from_node_args(ast, 1, RNODE_BEGIN(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_BEGIN(node)->nd_body);
case NODE_RESCUE:
- return rb_ary_new_from_node_args(ast, 3, RNODE_RESCUE(node)->nd_head, RNODE_RESCUE(node)->nd_resq, RNODE_RESCUE(node)->nd_else);
+ return rb_ary_new_from_node_args(ast_value, 3, RNODE_RESCUE(node)->nd_head, RNODE_RESCUE(node)->nd_resq, RNODE_RESCUE(node)->nd_else);
case NODE_RESBODY:
- return rb_ary_new_from_node_args(ast, 3, RNODE_RESBODY(node)->nd_args, RNODE_RESBODY(node)->nd_body, RNODE_RESBODY(node)->nd_next);
+ return rb_ary_new_from_node_args(ast_value, 3, RNODE_RESBODY(node)->nd_args, RNODE_RESBODY(node)->nd_body, RNODE_RESBODY(node)->nd_next);
case NODE_ENSURE:
- return rb_ary_new_from_node_args(ast, 2, RNODE_ENSURE(node)->nd_head, RNODE_ENSURE(node)->nd_ensr);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_ENSURE(node)->nd_head, RNODE_ENSURE(node)->nd_ensr);
case NODE_AND:
case NODE_OR:
{
VALUE ary = rb_ary_new();
while (1) {
- rb_ary_push(ary, NEW_CHILD(ast, RNODE_AND(node)->nd_1st));
+ rb_ary_push(ary, NEW_CHILD(ast_value, RNODE_AND(node)->nd_1st));
if (!RNODE_AND(node)->nd_2nd || !nd_type_p(RNODE_AND(node)->nd_2nd, type))
break;
node = RNODE_AND(node)->nd_2nd;
}
- rb_ary_push(ary, NEW_CHILD(ast, RNODE_AND(node)->nd_2nd));
+ rb_ary_push(ary, NEW_CHILD(ast_value, RNODE_AND(node)->nd_2nd));
return ary;
}
case NODE_MASGN:
if (NODE_NAMED_REST_P(RNODE_MASGN(node)->nd_args)) {
- return rb_ary_new_from_node_args(ast, 3, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head, RNODE_MASGN(node)->nd_args);
+ return rb_ary_new_from_node_args(ast_value, 3, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head, RNODE_MASGN(node)->nd_args);
}
else {
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_MASGN(node)->nd_value),
- NEW_CHILD(ast, RNODE_MASGN(node)->nd_head),
+ return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_MASGN(node)->nd_value),
+ NEW_CHILD(ast_value, RNODE_MASGN(node)->nd_head),
no_name_rest());
}
case NODE_LASGN:
if (NODE_REQUIRED_KEYWORD_P(RNODE_LASGN(node)->nd_value)) {
return rb_ary_new_from_args(2, var_name(RNODE_LASGN(node)->nd_vid), ID2SYM(rb_intern("NODE_SPECIAL_REQUIRED_KEYWORD")));
}
- return rb_ary_new_from_args(2, var_name(RNODE_LASGN(node)->nd_vid), NEW_CHILD(ast, RNODE_LASGN(node)->nd_value));
+ return rb_ary_new_from_args(2, var_name(RNODE_LASGN(node)->nd_vid), NEW_CHILD(ast_value, RNODE_LASGN(node)->nd_value));
case NODE_DASGN:
if (NODE_REQUIRED_KEYWORD_P(RNODE_DASGN(node)->nd_value)) {
return rb_ary_new_from_args(2, var_name(RNODE_DASGN(node)->nd_vid), ID2SYM(rb_intern("NODE_SPECIAL_REQUIRED_KEYWORD")));
}
- return rb_ary_new_from_args(2, var_name(RNODE_DASGN(node)->nd_vid), NEW_CHILD(ast, RNODE_DASGN(node)->nd_value));
+ return rb_ary_new_from_args(2, var_name(RNODE_DASGN(node)->nd_vid), NEW_CHILD(ast_value, RNODE_DASGN(node)->nd_value));
case NODE_IASGN:
- return rb_ary_new_from_args(2, var_name(RNODE_IASGN(node)->nd_vid), NEW_CHILD(ast, RNODE_IASGN(node)->nd_value));
+ return rb_ary_new_from_args(2, var_name(RNODE_IASGN(node)->nd_vid), NEW_CHILD(ast_value, RNODE_IASGN(node)->nd_value));
case NODE_CVASGN:
- return rb_ary_new_from_args(2, var_name(RNODE_CVASGN(node)->nd_vid), NEW_CHILD(ast, RNODE_CVASGN(node)->nd_value));
+ return rb_ary_new_from_args(2, var_name(RNODE_CVASGN(node)->nd_vid), NEW_CHILD(ast_value, RNODE_CVASGN(node)->nd_value));
case NODE_GASGN:
- return rb_ary_new_from_args(2, var_name(RNODE_GASGN(node)->nd_vid), NEW_CHILD(ast, RNODE_GASGN(node)->nd_value));
+ return rb_ary_new_from_args(2, var_name(RNODE_GASGN(node)->nd_vid), NEW_CHILD(ast_value, RNODE_GASGN(node)->nd_value));
case NODE_CDECL:
if (RNODE_CDECL(node)->nd_vid) {
- return rb_ary_new_from_args(2, ID2SYM(RNODE_CDECL(node)->nd_vid), NEW_CHILD(ast, RNODE_CDECL(node)->nd_value));
+ 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, RNODE_CDECL(node)->nd_else), ID2SYM(RNODE_COLON2(RNODE_CDECL(node)->nd_else)->nd_mid), NEW_CHILD(ast, RNODE_CDECL(node)->nd_value));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast_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));
case NODE_OP_ASGN1:
- return rb_ary_new_from_args(4, NEW_CHILD(ast, RNODE_OP_ASGN1(node)->nd_recv),
+ return rb_ary_new_from_args(4, NEW_CHILD(ast_value, RNODE_OP_ASGN1(node)->nd_recv),
ID2SYM(RNODE_OP_ASGN1(node)->nd_mid),
- NEW_CHILD(ast, RNODE_OP_ASGN1(node)->nd_index),
- NEW_CHILD(ast, RNODE_OP_ASGN1(node)->nd_rvalue));
+ NEW_CHILD(ast_value, RNODE_OP_ASGN1(node)->nd_index),
+ NEW_CHILD(ast_value, RNODE_OP_ASGN1(node)->nd_rvalue));
case NODE_OP_ASGN2:
- return rb_ary_new_from_args(5, NEW_CHILD(ast, RNODE_OP_ASGN2(node)->nd_recv),
+ return rb_ary_new_from_args(5, NEW_CHILD(ast_value, RNODE_OP_ASGN2(node)->nd_recv),
RBOOL(RNODE_OP_ASGN2(node)->nd_aid),
ID2SYM(RNODE_OP_ASGN2(node)->nd_vid),
ID2SYM(RNODE_OP_ASGN2(node)->nd_mid),
- NEW_CHILD(ast, RNODE_OP_ASGN2(node)->nd_value));
+ NEW_CHILD(ast_value, RNODE_OP_ASGN2(node)->nd_value));
case NODE_OP_ASGN_AND:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_OP_ASGN_AND(node)->nd_head), ID2SYM(idANDOP),
- NEW_CHILD(ast, RNODE_OP_ASGN_AND(node)->nd_value));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_OP_ASGN_AND(node)->nd_head), ID2SYM(idANDOP),
+ NEW_CHILD(ast_value, RNODE_OP_ASGN_AND(node)->nd_value));
case NODE_OP_ASGN_OR:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_OP_ASGN_OR(node)->nd_head), ID2SYM(idOROP),
- NEW_CHILD(ast, RNODE_OP_ASGN_OR(node)->nd_value));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_OP_ASGN_OR(node)->nd_head), ID2SYM(idOROP),
+ NEW_CHILD(ast_value, RNODE_OP_ASGN_OR(node)->nd_value));
case NODE_OP_CDECL:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_OP_CDECL(node)->nd_head),
+ return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_OP_CDECL(node)->nd_head),
ID2SYM(RNODE_OP_CDECL(node)->nd_aid),
- NEW_CHILD(ast, RNODE_OP_CDECL(node)->nd_value));
+ NEW_CHILD(ast_value, RNODE_OP_CDECL(node)->nd_value));
case NODE_CALL:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_CALL(node)->nd_recv),
+ return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_CALL(node)->nd_recv),
ID2SYM(RNODE_CALL(node)->nd_mid),
- NEW_CHILD(ast, RNODE_CALL(node)->nd_args));
+ NEW_CHILD(ast_value, RNODE_CALL(node)->nd_args));
case NODE_OPCALL:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_OPCALL(node)->nd_recv),
+ return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_OPCALL(node)->nd_recv),
ID2SYM(RNODE_OPCALL(node)->nd_mid),
- NEW_CHILD(ast, RNODE_OPCALL(node)->nd_args));
+ NEW_CHILD(ast_value, RNODE_OPCALL(node)->nd_args));
case NODE_QCALL:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_QCALL(node)->nd_recv),
+ return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_QCALL(node)->nd_recv),
ID2SYM(RNODE_QCALL(node)->nd_mid),
- NEW_CHILD(ast, RNODE_QCALL(node)->nd_args));
+ NEW_CHILD(ast_value, RNODE_QCALL(node)->nd_args));
case NODE_FCALL:
return rb_ary_new_from_args(2, ID2SYM(RNODE_FCALL(node)->nd_mid),
- NEW_CHILD(ast, RNODE_FCALL(node)->nd_args));
+ NEW_CHILD(ast_value, RNODE_FCALL(node)->nd_args));
case NODE_VCALL:
return rb_ary_new_from_args(1, ID2SYM(RNODE_VCALL(node)->nd_mid));
case NODE_SUPER:
- return rb_ary_new_from_node_args(ast, 1, RNODE_SUPER(node)->nd_args);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_SUPER(node)->nd_args);
case NODE_ZSUPER:
- return rb_ary_new_from_node_args(ast, 0);
+ return rb_ary_new_from_node_args(ast_value, 0);
case NODE_LIST:
- return dump_array(ast, RNODE_LIST(node));
+ return dump_array(ast_value, RNODE_LIST(node));
case NODE_ZLIST:
- return rb_ary_new_from_node_args(ast, 0);
+ return rb_ary_new_from_node_args(ast_value, 0);
case NODE_HASH:
- return rb_ary_new_from_node_args(ast, 1, RNODE_HASH(node)->nd_head);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_HASH(node)->nd_head);
case NODE_YIELD:
- return rb_ary_new_from_node_args(ast, 1, RNODE_YIELD(node)->nd_head);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_YIELD(node)->nd_head);
case NODE_LVAR:
return rb_ary_new_from_args(1, var_name(RNODE_LVAR(node)->nd_vid));
case NODE_DVAR:
@@ -532,11 +523,11 @@ node_children(rb_ast_t *ast, const NODE *node)
return rb_ary_new_from_args(1, rb_node_regx_string_val(node));
case NODE_MATCH2:
if (RNODE_MATCH2(node)->nd_args) {
- return rb_ary_new_from_node_args(ast, 3, RNODE_MATCH2(node)->nd_recv, RNODE_MATCH2(node)->nd_value, RNODE_MATCH2(node)->nd_args);
+ return rb_ary_new_from_node_args(ast_value, 3, RNODE_MATCH2(node)->nd_recv, RNODE_MATCH2(node)->nd_value, RNODE_MATCH2(node)->nd_args);
}
- return rb_ary_new_from_node_args(ast, 2, RNODE_MATCH2(node)->nd_recv, RNODE_MATCH2(node)->nd_value);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_MATCH2(node)->nd_recv, RNODE_MATCH2(node)->nd_value);
case NODE_MATCH3:
- return rb_ary_new_from_node_args(ast, 2, RNODE_MATCH3(node)->nd_recv, RNODE_MATCH3(node)->nd_value);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_MATCH3(node)->nd_recv, RNODE_MATCH3(node)->nd_value);
case NODE_STR:
case NODE_XSTR:
return rb_ary_new_from_args(1, rb_node_str_string_val(node));
@@ -551,7 +542,7 @@ node_children(rb_ast_t *ast, const NODE *node)
case NODE_REGX:
return rb_ary_new_from_args(1, rb_node_regx_string_val(node));
case NODE_ONCE:
- return rb_ary_new_from_node_args(ast, 1, RNODE_ONCE(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_ONCE(node)->nd_body);
case NODE_DSTR:
case NODE_DXSTR:
case NODE_DREGX:
@@ -560,91 +551,91 @@ node_children(rb_ast_t *ast, const NODE *node)
struct RNode_LIST *n = RNODE_DSTR(node)->nd_next;
VALUE head = Qnil, next = Qnil;
if (n) {
- head = NEW_CHILD(ast, n->nd_head);
- next = NEW_CHILD(ast, n->nd_next);
+ head = NEW_CHILD(ast_value, n->nd_head);
+ next = NEW_CHILD(ast_value, n->nd_next);
}
return rb_ary_new_from_args(3, rb_node_dstr_string_val(node), head, next);
}
case NODE_SYM:
return rb_ary_new_from_args(1, rb_node_sym_string_val(node));
case NODE_EVSTR:
- return rb_ary_new_from_node_args(ast, 1, RNODE_EVSTR(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_EVSTR(node)->nd_body);
case NODE_ARGSCAT:
- return rb_ary_new_from_node_args(ast, 2, RNODE_ARGSCAT(node)->nd_head, RNODE_ARGSCAT(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_ARGSCAT(node)->nd_head, RNODE_ARGSCAT(node)->nd_body);
case NODE_ARGSPUSH:
- return rb_ary_new_from_node_args(ast, 2, RNODE_ARGSPUSH(node)->nd_head, RNODE_ARGSPUSH(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_ARGSPUSH(node)->nd_head, RNODE_ARGSPUSH(node)->nd_body);
case NODE_SPLAT:
- return rb_ary_new_from_node_args(ast, 1, RNODE_SPLAT(node)->nd_head);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_SPLAT(node)->nd_head);
case NODE_BLOCK_PASS:
- return rb_ary_new_from_node_args(ast, 2, RNODE_BLOCK_PASS(node)->nd_head, RNODE_BLOCK_PASS(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_BLOCK_PASS(node)->nd_head, RNODE_BLOCK_PASS(node)->nd_body);
case NODE_DEFN:
- return rb_ary_new_from_args(2, ID2SYM(RNODE_DEFN(node)->nd_mid), NEW_CHILD(ast, RNODE_DEFN(node)->nd_defn));
+ return rb_ary_new_from_args(2, ID2SYM(RNODE_DEFN(node)->nd_mid), NEW_CHILD(ast_value, RNODE_DEFN(node)->nd_defn));
case NODE_DEFS:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_DEFS(node)->nd_recv), ID2SYM(RNODE_DEFS(node)->nd_mid), NEW_CHILD(ast, RNODE_DEFS(node)->nd_defn));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_DEFS(node)->nd_recv), ID2SYM(RNODE_DEFS(node)->nd_mid), NEW_CHILD(ast_value, RNODE_DEFS(node)->nd_defn));
case NODE_ALIAS:
- return rb_ary_new_from_node_args(ast, 2, RNODE_ALIAS(node)->nd_1st, RNODE_ALIAS(node)->nd_2nd);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_ALIAS(node)->nd_1st, RNODE_ALIAS(node)->nd_2nd);
case NODE_VALIAS:
return rb_ary_new_from_args(2, ID2SYM(RNODE_VALIAS(node)->nd_alias), ID2SYM(RNODE_VALIAS(node)->nd_orig));
case NODE_UNDEF:
- return rb_ary_new_from_node_args(ast, 1, RNODE_UNDEF(node)->nd_undef);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_UNDEF(node)->nd_undef);
case NODE_CLASS:
- return rb_ary_new_from_node_args(ast, 3, RNODE_CLASS(node)->nd_cpath, RNODE_CLASS(node)->nd_super, RNODE_CLASS(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 3, RNODE_CLASS(node)->nd_cpath, RNODE_CLASS(node)->nd_super, RNODE_CLASS(node)->nd_body);
case NODE_MODULE:
- return rb_ary_new_from_node_args(ast, 2, RNODE_MODULE(node)->nd_cpath, RNODE_MODULE(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_MODULE(node)->nd_cpath, RNODE_MODULE(node)->nd_body);
case NODE_SCLASS:
- return rb_ary_new_from_node_args(ast, 2, RNODE_SCLASS(node)->nd_recv, RNODE_SCLASS(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_SCLASS(node)->nd_recv, RNODE_SCLASS(node)->nd_body);
case NODE_COLON2:
- return rb_ary_new_from_args(2, NEW_CHILD(ast, RNODE_COLON2(node)->nd_head), ID2SYM(RNODE_COLON2(node)->nd_mid));
+ return rb_ary_new_from_args(2, NEW_CHILD(ast_value, RNODE_COLON2(node)->nd_head), ID2SYM(RNODE_COLON2(node)->nd_mid));
case NODE_COLON3:
return rb_ary_new_from_args(1, ID2SYM(RNODE_COLON3(node)->nd_mid));
case NODE_DOT2:
case NODE_DOT3:
case NODE_FLIP2:
case NODE_FLIP3:
- return rb_ary_new_from_node_args(ast, 2, RNODE_DOT2(node)->nd_beg, RNODE_DOT2(node)->nd_end);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_DOT2(node)->nd_beg, RNODE_DOT2(node)->nd_end);
case NODE_SELF:
- return rb_ary_new_from_node_args(ast, 0);
+ return rb_ary_new_from_node_args(ast_value, 0);
case NODE_NIL:
- return rb_ary_new_from_node_args(ast, 0);
+ return rb_ary_new_from_node_args(ast_value, 0);
case NODE_TRUE:
- return rb_ary_new_from_node_args(ast, 0);
+ return rb_ary_new_from_node_args(ast_value, 0);
case NODE_FALSE:
- return rb_ary_new_from_node_args(ast, 0);
+ return rb_ary_new_from_node_args(ast_value, 0);
case NODE_ERRINFO:
- return rb_ary_new_from_node_args(ast, 0);
+ return rb_ary_new_from_node_args(ast_value, 0);
case NODE_DEFINED:
- return rb_ary_new_from_node_args(ast, 1, RNODE_DEFINED(node)->nd_head);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_DEFINED(node)->nd_head);
case NODE_POSTEXE:
- return rb_ary_new_from_node_args(ast, 1, RNODE_POSTEXE(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_POSTEXE(node)->nd_body);
case NODE_ATTRASGN:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_ATTRASGN(node)->nd_recv), ID2SYM(RNODE_ATTRASGN(node)->nd_mid), NEW_CHILD(ast, RNODE_ATTRASGN(node)->nd_args));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_ATTRASGN(node)->nd_recv), ID2SYM(RNODE_ATTRASGN(node)->nd_mid), NEW_CHILD(ast_value, RNODE_ATTRASGN(node)->nd_args));
case NODE_LAMBDA:
- return rb_ary_new_from_node_args(ast, 1, RNODE_LAMBDA(node)->nd_body);
+ return rb_ary_new_from_node_args(ast_value, 1, RNODE_LAMBDA(node)->nd_body);
case NODE_OPT_ARG:
- return rb_ary_new_from_node_args(ast, 2, RNODE_OPT_ARG(node)->nd_body, RNODE_OPT_ARG(node)->nd_next);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_OPT_ARG(node)->nd_body, RNODE_OPT_ARG(node)->nd_next);
case NODE_KW_ARG:
- return rb_ary_new_from_node_args(ast, 2, RNODE_KW_ARG(node)->nd_body, RNODE_KW_ARG(node)->nd_next);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_KW_ARG(node)->nd_body, RNODE_KW_ARG(node)->nd_next);
case NODE_POSTARG:
if (NODE_NAMED_REST_P(RNODE_POSTARG(node)->nd_1st)) {
- return rb_ary_new_from_node_args(ast, 2, RNODE_POSTARG(node)->nd_1st, RNODE_POSTARG(node)->nd_2nd);
+ return rb_ary_new_from_node_args(ast_value, 2, RNODE_POSTARG(node)->nd_1st, RNODE_POSTARG(node)->nd_2nd);
}
return rb_ary_new_from_args(2, no_name_rest(),
- NEW_CHILD(ast, RNODE_POSTARG(node)->nd_2nd));
+ NEW_CHILD(ast_value, RNODE_POSTARG(node)->nd_2nd));
case NODE_ARGS:
{
struct rb_args_info *ainfo = &RNODE_ARGS(node)->nd_ainfo;
return rb_ary_new_from_args(10,
INT2NUM(ainfo->pre_args_num),
- NEW_CHILD(ast, ainfo->pre_init),
- NEW_CHILD(ast, (NODE *)ainfo->opt_args),
+ NEW_CHILD(ast_value, ainfo->pre_init),
+ NEW_CHILD(ast_value, (NODE *)ainfo->opt_args),
var_name(ainfo->first_post_arg),
INT2NUM(ainfo->post_args_num),
- NEW_CHILD(ast, ainfo->post_init),
+ NEW_CHILD(ast_value, ainfo->post_init),
(ainfo->rest_arg == NODE_SPECIAL_EXCESSIVE_COMMA
? ID2SYM(rb_intern("NODE_SPECIAL_EXCESSIVE_COMMA"))
: var_name(ainfo->rest_arg)),
- (ainfo->no_kwarg ? Qfalse : NEW_CHILD(ast, (NODE *)ainfo->kw_args)),
- (ainfo->no_kwarg ? Qfalse : NEW_CHILD(ast, ainfo->kw_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));
}
case NODE_SCOPE:
@@ -655,35 +646,35 @@ node_children(rb_ast_t *ast, const NODE *node)
for (i = 0; i < size; i++) {
rb_ary_push(locals, var_name(tbl->ids[i]));
}
- return rb_ary_new_from_args(3, locals, NEW_CHILD(ast, (NODE *)RNODE_SCOPE(node)->nd_args), NEW_CHILD(ast, RNODE_SCOPE(node)->nd_body));
+ return rb_ary_new_from_args(3, locals, NEW_CHILD(ast_value, (NODE *)RNODE_SCOPE(node)->nd_args), NEW_CHILD(ast_value, RNODE_SCOPE(node)->nd_body));
}
case NODE_ARYPTN:
{
- VALUE rest = rest_arg(ast, RNODE_ARYPTN(node)->rest_arg);
+ VALUE rest = rest_arg(ast_value, RNODE_ARYPTN(node)->rest_arg);
return rb_ary_new_from_args(4,
- NEW_CHILD(ast, RNODE_ARYPTN(node)->nd_pconst),
- NEW_CHILD(ast, RNODE_ARYPTN(node)->pre_args),
+ NEW_CHILD(ast_value, RNODE_ARYPTN(node)->nd_pconst),
+ NEW_CHILD(ast_value, RNODE_ARYPTN(node)->pre_args),
rest,
- NEW_CHILD(ast, RNODE_ARYPTN(node)->post_args));
+ NEW_CHILD(ast_value, RNODE_ARYPTN(node)->post_args));
}
case NODE_FNDPTN:
{
- VALUE pre_rest = rest_arg(ast, RNODE_FNDPTN(node)->pre_rest_arg);
- VALUE post_rest = rest_arg(ast, RNODE_FNDPTN(node)->post_rest_arg);
+ VALUE pre_rest = rest_arg(ast_value, RNODE_FNDPTN(node)->pre_rest_arg);
+ VALUE post_rest = rest_arg(ast_value, RNODE_FNDPTN(node)->post_rest_arg);
return rb_ary_new_from_args(4,
- NEW_CHILD(ast, RNODE_FNDPTN(node)->nd_pconst),
+ NEW_CHILD(ast_value, RNODE_FNDPTN(node)->nd_pconst),
pre_rest,
- NEW_CHILD(ast, RNODE_FNDPTN(node)->args),
+ NEW_CHILD(ast_value, RNODE_FNDPTN(node)->args),
post_rest);
}
case NODE_HSHPTN:
{
VALUE kwrest = RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD ? ID2SYM(rb_intern("NODE_SPECIAL_NO_REST_KEYWORD")) :
- NEW_CHILD(ast, RNODE_HSHPTN(node)->nd_pkwrestarg);
+ NEW_CHILD(ast_value, RNODE_HSHPTN(node)->nd_pkwrestarg);
return rb_ary_new_from_args(3,
- NEW_CHILD(ast, RNODE_HSHPTN(node)->nd_pconst),
- NEW_CHILD(ast, RNODE_HSHPTN(node)->nd_pkwargs),
+ NEW_CHILD(ast_value, RNODE_HSHPTN(node)->nd_pconst),
+ NEW_CHILD(ast_value, RNODE_HSHPTN(node)->nd_pkwargs),
kwrest);
}
case NODE_LINE:
@@ -693,7 +684,7 @@ node_children(rb_ast_t *ast, const NODE *node)
case NODE_ENCODING:
return rb_ary_new_from_args(1, rb_node_encoding_val(node));
case NODE_ERROR:
- return rb_ary_new_from_node_args(ast, 0);
+ return rb_ary_new_from_node_args(ast_value, 0);
case NODE_ARGS_AUX:
case NODE_LAST:
break;
@@ -708,7 +699,7 @@ ast_node_children(rb_execution_context_t *ec, VALUE self)
struct ASTNodeData *data;
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
- return node_children(data->ast, data->node);
+ return node_children(data->ast_value, data->node);
}
static VALUE
@@ -752,13 +743,15 @@ ast_node_all_tokens(rb_execution_context_t *ec, VALUE self)
{
long i;
struct ASTNodeData *data;
+ rb_ast_t *ast;
rb_parser_ary_t *parser_tokens;
rb_parser_ast_token_t *parser_token;
VALUE str, loc, token, all_tokens;
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
+ ast = rb_ruby_ast_data_get(data->ast_value);
- parser_tokens = data->ast->node_buffer->tokens;
+ parser_tokens = ast->node_buffer->tokens;
if (parser_tokens == NULL) {
return Qnil;
}
@@ -805,9 +798,10 @@ static VALUE
ast_node_script_lines(rb_execution_context_t *ec, VALUE self)
{
struct ASTNodeData *data;
+ rb_ast_t *ast;
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
- rb_parser_ary_t *ret = data->ast->body.script_lines;
- if (!ret || FIXNUM_P((VALUE)ret)) return Qnil;
+ ast = rb_ruby_ast_data_get(data->ast_value);
+ rb_parser_ary_t *ret = ast->body.script_lines;
return rb_parser_build_script_lines_from(ret);
}
diff --git a/bootstraptest/runner.rb b/bootstraptest/runner.rb
index 20f121cdf4..120b78246c 100755
--- a/bootstraptest/runner.rb
+++ b/bootstraptest/runner.rb
@@ -76,6 +76,8 @@ bt = Struct.new(:ruby,
:width,
:indent,
:platform,
+ :timeout,
+ :timeout_scale,
)
BT = Class.new(bt) do
def indent=(n)
@@ -143,6 +145,10 @@ BT = Class.new(bt) do
end
super wn
end
+
+ def apply_timeout_scale(timeout)
+ timeout&.*(timeout_scale)
+ end
end.new
BT_STATE = Struct.new(:count, :error).new
@@ -155,6 +161,8 @@ def main
BT.color = nil
BT.tty = nil
BT.quiet = false
+ BT.timeout = 180
+ BT.timeout_scale = (defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? ? 3 : 1) # for --jit-wait
# BT.wn = 1
dir = nil
quiet = false
@@ -185,14 +193,18 @@ def main
warn "unknown --tty argument: #$3" if $3
BT.tty = !$1 || !$2
true
- when /\A(-q|--q(uiet))\z/
+ when /\A(-q|--q(uiet)?)\z/
quiet = true
BT.quiet = true
true
when /\A-j(\d+)?/
BT.wn = $1.to_i
true
- when /\A(-v|--v(erbose))\z/
+ when /\A--timeout=(\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?)(?::(\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?))?/
+ BT.timeout = $1.to_f
+ BT.timeout_scale = $2.to_f if defined?($2)
+ true
+ when /\A(-v|--v(erbose)?)\z/
BT.verbose = true
BT.quiet = false
true
@@ -204,6 +216,7 @@ Usage: #{File.basename($0, '.*')} --ruby=PATH [--sets=NAME,NAME,...]
default: /tmp/bootstraptestXXXXX.tmpwd
--color[=WHEN] Colorize the output. WHEN defaults to 'always'
or can be 'never' or 'auto'.
+ --timeout=TIMEOUT Default timeout in seconds.
-s, --stress stress test.
-v, --verbose Output test name before exec.
-q, --quiet Don\'t print header message.
@@ -525,14 +538,16 @@ class Assertion < Struct.new(:src, :path, :lineno, :proc)
end
end
- def get_result_string(opt = '', **argh)
+ def get_result_string(opt = '', timeout: BT.timeout, **argh)
if BT.ruby
+ timeout = BT.apply_timeout_scale(timeout)
filename = make_srcfile(**argh)
begin
kw = self.err ? {err: self.err} : {}
out = IO.popen("#{BT.ruby} -W0 #{opt} #{filename}", **kw)
pid = out.pid
- out.read.tap{ Process.waitpid(pid); out.close }
+ th = Thread.new {out.read.tap {Process.waitpid(pid); out.close}}
+ th.value if th.join(timeout)
ensure
raise Interrupt if $? and $?.signaled? && $?.termsig == Signal.list["INT"]
@@ -618,8 +633,9 @@ def assert_valid_syntax(testsrc, message = '')
end
end
-def assert_normal_exit(testsrc, *rest, timeout: nil, **opt)
+def assert_normal_exit(testsrc, *rest, timeout: BT.timeout, **opt)
add_assertion testsrc, -> as do
+ timeout = BT.apply_timeout_scale(timeout)
message, ignore_signals = rest
message ||= ''
as.show_progress(message) {
@@ -673,9 +689,7 @@ end
def assert_finish(timeout_seconds, testsrc, message = '')
add_assertion testsrc, -> as do
- if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # for --jit-wait
- timeout_seconds *= 3
- end
+ timeout_seconds = BT.apply_timeout_scale(timeout_seconds)
as.show_progress(message) {
faildesc = nil
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index 4868810308..0390d38f9c 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -601,7 +601,7 @@ assert_equal '{:ok=>3}', %q{
end
3.times.map{Ractor.receive}.tally
-}
+} unless yjit_enabled? # `[BUG] Bus Error at 0x000000010b7002d0` in jit_exec()
# unshareable object are copied
assert_equal 'false', %q{
@@ -1466,6 +1466,25 @@ assert_equal '[:ok, :ok]', %q{
end
}
+# Ractor.select is interruptible
+assert_normal_exit %q{
+ trap(:INT) do
+ exit
+ end
+
+ r = Ractor.new do
+ loop do
+ sleep 1
+ end
+ end
+
+ Thread.new do
+ sleep 0.5
+ Process.kill(:INT, Process.pid)
+ end
+ Ractor.select(r)
+}
+
# Ractor-local storage
assert_equal '[nil, "b", "a"]', %q{
ans = []
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index 6b7d483926..8b8f7d1e39 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -2317,6 +2317,19 @@ assert_equal '123', %q{
foo(Foo)
}
+# Test EP == BP invalidation with moving ISEQs
+assert_equal 'ok', %q{
+ def entry
+ ok = proc { :ok } # set #entry as an EP-escaping ISEQ
+ [nil].reverse_each do # avoid exiting the JIT frame on the constant
+ GC.compact # move #entry ISEQ
+ end
+ ok # should be read off of escaped EP
+ end
+
+ entry.call
+}
+
# invokesuper edge case
assert_equal '[:A, [:A, :B]]', %q{
class B
@@ -4770,6 +4783,19 @@ assert_equal '[:ok, :ok, :ok]', %q{
tests
}
+# regression test for invalidating an empty block
+assert_equal '0', %q{
+ def foo = (* = 1).pred
+
+ foo # compile it
+
+ class Integer
+ def to_ary = [] # invalidate
+ end
+
+ foo # try again
+} unless rjit_enabled? # doesn't work on RJIT
+
# test integer left shift with constant rhs
assert_equal [0x80000000000, 'a+', :ok].inspect, %q{
def shift(val) = val << 43
@@ -4786,3 +4812,171 @@ assert_equal [0x80000000000, 'a+', :ok].inspect, %q{
tests
}
+
+# test String#stebyte with arguments that need conversion
+assert_equal "abc", %q{
+ str = +"a00"
+ def change_bytes(str, one, two)
+ str.setbyte(one, "b".ord)
+ str.setbyte(2, two)
+ end
+
+ to_int_1 = Object.new
+ to_int_99 = Object.new
+ def to_int_1.to_int = 1
+ def to_int_99.to_int = 99
+
+ change_bytes(str, to_int_1, to_int_99)
+ str
+}
+
+# test --yjit-verify-ctx for arrays with a singleton class
+assert_equal "ok", %q{
+ class Array
+ def foo
+ self.singleton_class.define_method(:first) { :ok }
+ first
+ end
+ end
+
+ def test = [].foo
+
+ test
+}
+
+assert_equal '["raised", "Module", "Object"]', %q{
+ def foo(obj)
+ obj.superclass.name
+ end
+
+ ret = []
+
+ begin
+ foo(Class.allocate)
+ rescue TypeError
+ ret << 'raised'
+ end
+
+ ret += [foo(Class), foo(Class.new)]
+}
+
+# test TrueClass#=== before and after redefining TrueClass#==
+assert_equal '[[true, false, false], [true, true, false], [true, :error, :error]]', %q{
+ def true_eqq(x)
+ true === x
+ rescue NoMethodError
+ :error
+ end
+
+ def test
+ [
+ # first one is always true because rb_equal does object comparison before calling #==
+ true_eqq(true),
+ # these will use TrueClass#==
+ true_eqq(false),
+ true_eqq(:truthy),
+ ]
+ end
+
+ results = [test]
+
+ class TrueClass
+ def ==(x)
+ !x
+ end
+ end
+
+ results << test
+
+ class TrueClass
+ undef_method :==
+ end
+
+ results << test
+} unless rjit_enabled? # Not yet working on RJIT
+
+# test FalseClass#=== before and after redefining FalseClass#==
+assert_equal '[[true, false, false], [true, false, true], [true, :error, :error]]', %q{
+ def case_equal(x, y)
+ x === y
+ rescue NoMethodError
+ :error
+ end
+
+ def test
+ [
+ # first one is always true because rb_equal does object comparison before calling #==
+ case_equal(false, false),
+ # these will use #==
+ case_equal(false, true),
+ case_equal(false, nil),
+ ]
+ end
+
+ results = [test]
+
+ class FalseClass
+ def ==(x)
+ !x
+ end
+ end
+
+ results << test
+
+ class FalseClass
+ undef_method :==
+ end
+
+ results << test
+} unless rjit_enabled? # Not yet working on RJIT
+
+# test NilClass#=== before and after redefining NilClass#==
+assert_equal '[[true, false, false], [true, false, true], [true, :error, :error]]', %q{
+ def case_equal(x, y)
+ x === y
+ rescue NoMethodError
+ :error
+ end
+
+ def test
+ [
+ # first one is always true because rb_equal does object comparison before calling #==
+ case_equal(nil, nil),
+ # these will use #==
+ case_equal(nil, true),
+ case_equal(nil, false),
+ ]
+ end
+
+ results = [test]
+
+ class NilClass
+ def ==(x)
+ !x
+ end
+ end
+
+ results << test
+
+ class NilClass
+ undef_method :==
+ end
+
+ results << test
+} unless rjit_enabled? # Not yet working on RJIT
+
+# test struct accessors fire c_call events
+assert_equal '[[:c_call, :x=], [:c_call, :x]]', %q{
+ c = Struct.new(:x)
+ obj = c.new
+
+ events = []
+ TracePoint.new(:c_call) do
+ events << [_1.event, _1.method_id]
+ end.enable do
+ obj.x = 100
+ obj.x
+ end
+
+ events
+}
diff --git a/common.mk b/common.mk
index 77aa8b04ff..18641efd7f 100644
--- a/common.mk
+++ b/common.mk
@@ -216,6 +216,11 @@ 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
@@ -411,7 +416,7 @@ configure-ext: $(EXTS_MK)
build-ext: $(EXTS_MK)
$(Q)$(MAKE) -f $(EXTS_MK) $(mflags) libdir="$(libdir)" LIBRUBY_EXTS=$(LIBRUBY_EXTS) \
EXTENCS="$(ENCOBJS)" BASERUBY="$(BASERUBY)" MINIRUBY="$(MINIRUBY)" \
- UPDATE_LIBRARIES=no $(EXTSTATIC)
+ $(EXTSTATIC)
$(Q)$(MAKE) $(EXTS_NOTE)
exts-note: $(EXTS_MK)
@@ -483,9 +488,9 @@ docs: srcs-doc $(DOCTARGETS)
pkgconfig-data: $(ruby_pc)
$(ruby_pc): $(srcdir)/template/ruby.pc.in config.status
-install-all: pre-install-all docs do-install-all post-install-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
+do-install-all: pre-install-all $(DOT_WAIT) docs
$(INSTRUBY) --make="$(MAKE)" $(INSTRUBY_ARGS) --install=all $(INSTALL_DOC_OPTS)
post-install-all:: post-install-local post-install-ext post-install-gem post-install-doc
@$(NULLCMD)
@@ -957,12 +962,16 @@ PRECHECK_TEST_ALL = yes-test-all-precheck
test-all: $(TEST_RUNNABLE)-test-all
yes-test-all: $(PRECHECK_TEST_ALL)
$(ACTIONS_GROUP)
- $(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) "$(TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" \
+ $(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) -r$(tooldir)/lib/_tmpdir \
+ "$(TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" \
$(TEST_EXCLUDES) $(TESTOPTS) $(TESTS)
$(ACTIONS_ENDGROUP)
TESTS_BUILD = mkmf
no-test-all: PHONY
- $(gnumake_recursive)$(MINIRUBY) -I"$(srcdir)/lib" "$(TESTSDIR)/runner.rb" $(TESTOPTS) $(TESTS_BUILD)
+ $(ACTIONS_GROUP)
+ $(gnumake_recursive)$(MINIRUBY) -I"$(srcdir)/lib" -r$(tooldir)/lib/_tmpdir \
+ "$(TESTSDIR)/runner.rb" $(TESTOPTS) $(TESTS_BUILD)
+ $(ACTIONS_ENDGROUP)
test-almost: test-all
yes-test-almost: yes-test-all
@@ -1004,7 +1013,7 @@ test-spec: $(TEST_RUNNABLE)-test-spec
yes-test-spec: yes-test-spec-precheck
$(ACTIONS_GROUP)
$(gnumake_recursive)$(Q) \
- $(RUNRUBY) -r./$(arch)-fake -r$(tooldir)/rubyspec_temp \
+ $(RUNRUBY) -r./$(arch)-fake -r$(tooldir)/lib/_tmpdir \
$(srcdir)/spec/mspec/bin/mspec run -B $(srcdir)/spec/default.mspec $(MSPECOPT) $(SPECOPTS)
$(ACTIONS_ENDGROUP)
no-test-spec:
@@ -1013,7 +1022,7 @@ test-prism-spec: $(TEST_RUNNABLE)-test-prism-spec
yes-test-prism-spec: yes-test-spec-precheck
$(ACTIONS_GROUP)
$(gnumake_recursive)$(Q) \
- $(RUNRUBY) -r./$(arch)-fake -r$(tooldir)/rubyspec_temp \
+ $(RUNRUBY) -r./$(arch)-fake -r$(tooldir)/lib/_tmpdir \
$(srcdir)/spec/mspec/bin/mspec run -B $(srcdir)/spec/default.mspec -B $(srcdir)/spec/prism.mspec $(MSPECOPT) $(SPECOPTS)
$(ACTIONS_ENDGROUP)
no-test-prism-spec:
@@ -1606,35 +1615,13 @@ test-bundled-gems-spec: $(TEST_RUNNABLE)-test-bundled-gems-spec
yes-test-bundled-gems-spec: yes-test-spec-precheck $(PREPARE_BUNDLED_GEMS)
$(ACTIONS_GROUP)
$(gnumake_recursive)$(Q) \
- $(RUNRUBY) -r./$(arch)-fake -r$(tooldir)/rubyspec_temp \
+ $(RUNRUBY) -r./$(arch)-fake -r$(tooldir)/lib/_tmpdir \
$(srcdir)/spec/mspec/bin/mspec run -B $(srcdir)/spec/bundled_gems.mspec $(MSPECOPT) $(SPECOPTS)
$(ACTIONS_ENDGROUP)
no-test-bundled-gems-spec:
-test-syntax-suggest-precheck: $(TEST_RUNNABLE)-test-syntax-suggest-precheck
-no-test-syntax-suggest-precheck:
-yes-test-syntax-suggest-precheck: main
-
-test-syntax-suggest-prepare: $(TEST_RUNNABLE)-test-syntax-suggest-prepare
-no-test-syntax-suggest-prepare: no-test-syntax-suggest-precheck
-yes-test-syntax-suggest-prepare: yes-test-syntax-suggest-precheck
- $(ACTIONS_GROUP)
- $(XRUBY) -C "$(srcdir)" bin/gem install --no-document \
- --install-dir .bundle --conservative "rspec:~> 3"
- $(ACTIONS_ENDGROUP)
-RSPECOPTS =
-SYNTAX_SUGGEST_SPECS =
-PREPARE_SYNTAX_SUGGEST = $(TEST_RUNNABLE)-test-syntax-suggest-prepare
-test-syntax-suggest: $(TEST_RUNNABLE)-test-syntax-suggest
-yes-test-syntax-suggest: $(PREPARE_SYNTAX_SUGGEST)
- $(ACTIONS_GROUP)
- $(XRUBY) -C $(srcdir) -Ispec/syntax_suggest:spec/lib .bundle/bin/rspec \
- --require rspec/expectations \
- --require spec_helper --require formatter_overrides --require spec_coverage \
- $(RSPECOPTS) spec/syntax_suggest/$(SYNTAX_SUGGEST_SPECS)
- $(ACTIONS_ENDGROUP)
-no-test-syntax-suggest:
+test-syntax-suggest:
check: $(DOT_WAIT) $(PREPARE_SYNTAX_SUGGEST) test-syntax-suggest
@@ -2204,6 +2191,7 @@ 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
@@ -2439,6 +2427,7 @@ 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
@@ -2651,6 +2640,7 @@ 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
@@ -2875,6 +2865,7 @@ 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
@@ -3085,6 +3076,7 @@ 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
@@ -3278,6 +3270,7 @@ 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
@@ -3312,6 +3305,7 @@ 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
@@ -3515,6 +3509,7 @@ 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
@@ -3742,6 +3737,7 @@ 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
@@ -3975,6 +3971,7 @@ 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
@@ -4190,6 +4187,7 @@ 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
@@ -4368,6 +4366,7 @@ 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
@@ -4568,6 +4567,7 @@ 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
@@ -4744,6 +4744,7 @@ 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
@@ -4901,6 +4902,7 @@ 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
@@ -5057,6 +5059,7 @@ 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
@@ -6075,6 +6078,7 @@ 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
@@ -6284,6 +6288,7 @@ 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
@@ -6491,6 +6496,7 @@ 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
@@ -6706,6 +6712,7 @@ 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
@@ -6950,6 +6957,7 @@ 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
@@ -7189,6 +7197,7 @@ 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
@@ -7432,6 +7441,7 @@ 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
@@ -7490,6 +7500,7 @@ 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
@@ -7683,6 +7694,7 @@ 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
@@ -7926,6 +7938,7 @@ 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
@@ -8139,6 +8152,7 @@ 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
@@ -8316,6 +8330,7 @@ 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
@@ -8523,6 +8538,7 @@ 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
@@ -8729,6 +8745,7 @@ 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
@@ -8967,6 +8984,7 @@ 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
@@ -9220,6 +9238,7 @@ 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
@@ -9398,6 +9417,7 @@ 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
@@ -9567,6 +9587,7 @@ 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
@@ -9731,6 +9752,7 @@ 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
@@ -9936,6 +9958,7 @@ 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
@@ -10125,6 +10148,7 @@ 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
@@ -10315,6 +10339,7 @@ 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
@@ -10357,6 +10382,7 @@ 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
@@ -10553,6 +10579,7 @@ 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
@@ -10776,6 +10803,7 @@ 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
@@ -10816,6 +10844,7 @@ 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
@@ -10986,6 +11015,7 @@ 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
@@ -11200,6 +11230,7 @@ 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
@@ -11418,6 +11449,7 @@ 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
@@ -11630,6 +11662,7 @@ 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
@@ -11851,6 +11884,7 @@ 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
@@ -12128,6 +12162,7 @@ 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
@@ -12323,6 +12358,7 @@ 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
@@ -12532,6 +12568,7 @@ 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
@@ -12554,6 +12591,7 @@ 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
@@ -12579,6 +12617,7 @@ 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
@@ -12621,6 +12660,7 @@ 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
@@ -12731,6 +12771,7 @@ 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
@@ -12923,6 +12964,7 @@ 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
@@ -13146,6 +13188,7 @@ 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
@@ -13374,6 +13417,7 @@ 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
@@ -13596,6 +13640,7 @@ 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
@@ -13809,6 +13854,7 @@ 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
@@ -14015,6 +14061,7 @@ 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
@@ -14213,6 +14260,7 @@ 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
@@ -14425,6 +14473,7 @@ 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
@@ -14599,6 +14648,7 @@ 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
@@ -14760,6 +14810,7 @@ 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
@@ -14920,6 +14971,7 @@ 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
@@ -15080,6 +15132,7 @@ 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
@@ -15244,6 +15297,7 @@ 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
@@ -15405,6 +15459,7 @@ 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
@@ -15634,6 +15689,7 @@ rjit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
rjit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
rjit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
rjit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+rjit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
rjit.$(OBJEXT): {$(VPATH)}internal/symbol.h
rjit.$(OBJEXT): {$(VPATH)}internal/value.h
rjit.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -15886,6 +15942,7 @@ rjit_c.$(OBJEXT): {$(VPATH)}internal/special_consts.h
rjit_c.$(OBJEXT): {$(VPATH)}internal/static_assert.h
rjit_c.$(OBJEXT): {$(VPATH)}internal/stdalign.h
rjit_c.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+rjit_c.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
rjit_c.$(OBJEXT): {$(VPATH)}internal/symbol.h
rjit_c.$(OBJEXT): {$(VPATH)}internal/value.h
rjit_c.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -16162,6 +16219,7 @@ 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
@@ -16204,6 +16262,7 @@ 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
@@ -16368,6 +16427,7 @@ 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
@@ -16562,6 +16622,7 @@ 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
@@ -16733,6 +16794,7 @@ 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
@@ -16928,6 +16990,7 @@ 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
@@ -17139,6 +17202,7 @@ 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
@@ -17345,6 +17409,7 @@ 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
@@ -17518,6 +17583,7 @@ 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
@@ -17692,6 +17758,7 @@ 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
@@ -17900,6 +17967,7 @@ 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
@@ -18147,6 +18215,7 @@ 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
@@ -18359,6 +18428,7 @@ 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
@@ -18607,6 +18677,7 @@ 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
@@ -18833,6 +18904,7 @@ 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
@@ -19030,6 +19102,7 @@ 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
@@ -19198,6 +19271,7 @@ 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
@@ -19398,6 +19472,7 @@ 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
@@ -19609,6 +19684,7 @@ 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
@@ -19868,6 +19944,7 @@ 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
@@ -20122,6 +20199,7 @@ 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
@@ -20350,6 +20428,7 @@ 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
@@ -20560,6 +20639,7 @@ 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
@@ -20794,6 +20874,7 @@ 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
@@ -21003,6 +21084,7 @@ 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
@@ -21238,6 +21320,7 @@ 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
diff --git a/compile.c b/compile.c
index 853fadf5b0..5167f4d61c 100644
--- a/compile.c
+++ b/compile.c
@@ -612,11 +612,13 @@ branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
return 1;
}
+#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
+
static VALUE
-decl_branch_base(rb_iseq_t *iseq, const NODE *node, const char *type)
+decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
{
- const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
- const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
+ const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
+ const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
if (!branch_coverage_valid_p(iseq, first_lineno)) return Qundef;
@@ -629,7 +631,6 @@ decl_branch_base(rb_iseq_t *iseq, const NODE *node, const char *type)
*/
VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
- VALUE key = (VALUE)node | 1; // FIXNUM for hash key
VALUE branch_base = rb_hash_aref(structure, key);
VALUE branches;
@@ -662,10 +663,10 @@ generate_dummy_line_node(int lineno, int node_id)
}
static void
-add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *node, int branch_id, const char *type, VALUE branches)
+add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code_location_t *loc, int node_id, int branch_id, const char *type, VALUE branches)
{
- const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
- const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
+ const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
+ const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
if (!branch_coverage_valid_p(iseq, first_lineno)) return;
@@ -699,7 +700,7 @@ add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *n
}
ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
- ADD_SYNTHETIC_INSN(seq, last_lineno, nd_node_id(node), nop);
+ ADD_SYNTHETIC_INSN(seq, last_lineno, node_id, nop);
}
#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
@@ -1478,16 +1479,11 @@ new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
{
rb_iseq_t *ret_iseq;
- rb_ast_body_t ast;
-
- ast.root = node;
- ast.frozen_string_literal = -1;
- ast.coverage_enabled = -1;
- ast.script_lines = NULL;
+ VALUE ast_value = rb_ruby_ast_new(node);
debugs("[new_child_iseq]> ---------------------------------------\n");
int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
- ret_iseq = rb_iseq_new_with_opt(&ast, name,
+ ret_iseq = rb_iseq_new_with_opt(ast_value, name,
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
line_no, parent,
isolated_depth ? isolated_depth + 1 : 0,
@@ -2006,8 +2002,11 @@ iseq_set_use_block(rb_iseq_t *iseq)
body->param.flags.use_block = 1;
rb_vm_t *vm = GET_VM();
- st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
- st_insert(vm->unused_block_warning_table, key, 1);
+
+ if (!vm->unused_block_warning_strict) {
+ st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
+ st_insert(vm->unused_block_warning_table, key, 1);
+ }
}
}
@@ -5381,12 +5380,17 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
+ bool safenav_call = false;
LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
ASSUME(iobj);
- ELEM_REMOVE(LAST_ELEMENT(pre));
- ELEM_REMOVE((LINK_ELEMENT *)iobj);
- pre->last = iobj->link.prev;
+ ELEM_REMOVE(insn_element);
+ if (!IS_INSN_ID(iobj, send)) {
+ safenav_call = true;
+ iobj = (INSN *)get_prev_insn(iobj);
+ ELEM_INSERT_NEXT(&iobj->link, insn_element);
+ }
+ (pre->last = iobj->link.prev)->next = 0;
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
int argc = vm_ci_argc(ci) + 1;
@@ -5405,7 +5409,9 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
return COMPILE_NG;
}
- ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
+ iobj->link.prev = lhs->last;
+ lhs->last->next = &iobj->link;
+ for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
int argc = vm_ci_argc(ci);
bool dupsplat = false;
@@ -5438,9 +5444,11 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
}
INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
}
- ADD_INSN(lhs, line_node, pop);
- if (argc != 1) {
+ if (!safenav_call) {
ADD_INSN(lhs, line_node, pop);
+ if (argc != 1) {
+ ADD_INSN(lhs, line_node, pop);
+ }
}
for (int i=0; i < argc; i++) {
ADD_INSN(post, line_node, pop);
@@ -6443,7 +6451,7 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int
ADD_SEQ(ret, cond_seq);
if (then_label->refcnt && else_label->refcnt) {
- branches = decl_branch_base(iseq, node, type == NODE_IF ? "if" : "unless");
+ branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
}
if (then_label->refcnt) {
@@ -6454,10 +6462,12 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int
CHECK(COMPILE_(then_seq, "then", node_body, popped));
if (else_label->refcnt) {
+ const NODE *const coverage_node = node_body ? node_body : node;
add_trace_branch_coverage(
iseq,
ret,
- node_body ? node_body : node,
+ nd_code_loc(coverage_node),
+ nd_node_id(coverage_node),
0,
type == NODE_IF ? "then" : "else",
branches);
@@ -6478,10 +6488,12 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int
CHECK(COMPILE_(else_seq, "else", node_else, popped));
if (then_label->refcnt) {
+ const NODE *const coverage_node = node_else ? node_else : node;
add_trace_branch_coverage(
iseq,
ret,
- node_else ? node_else : node,
+ nd_code_loc(coverage_node),
+ nd_node_id(coverage_node),
1,
type == NODE_IF ? "else" : "then",
branches);
@@ -6521,7 +6533,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
- branches = decl_branch_base(iseq, node, "case");
+ branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
node = RNODE_CASE(node)->nd_body;
EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
@@ -6540,13 +6552,17 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
l1 = NEW_LABEL(line);
ADD_LABEL(body_seq, l1);
ADD_INSN(body_seq, line_node, pop);
+
+ const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
add_trace_branch_coverage(
iseq,
body_seq,
- RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node,
+ nd_code_loc(coverage_node),
+ nd_node_id(coverage_node),
branch_id++,
"when",
branches);
+
CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
ADD_INSNL(body_seq, line_node, jump, endlabel);
@@ -6583,7 +6599,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
if (node) {
ADD_LABEL(cond_seq, elselabel);
ADD_INSN(cond_seq, line_node, pop);
- add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
+ add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
CHECK(COMPILE_(cond_seq, "else", node, popped));
ADD_INSNL(cond_seq, line_node, jump, endlabel);
}
@@ -6591,7 +6607,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
debugs("== else (implicit)\n");
ADD_LABEL(cond_seq, elselabel);
ADD_INSN(cond_seq, orig_node, pop);
- add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
+ add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
if (!popped) {
ADD_INSN(cond_seq, orig_node, putnil);
}
@@ -6622,7 +6638,7 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
VALUE branches = Qfalse;
int branch_id = 0;
- branches = decl_branch_base(iseq, orig_node, "case");
+ branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
INIT_ANCHOR(body_seq);
endlabel = NEW_LABEL(nd_line(node));
@@ -6631,13 +6647,17 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
const int line = nd_line(node);
LABEL *l1 = NEW_LABEL(line);
ADD_LABEL(body_seq, l1);
+
+ const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
add_trace_branch_coverage(
iseq,
body_seq,
- RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node,
+ nd_code_loc(coverage_node),
+ nd_node_id(coverage_node),
branch_id++,
"when",
branches);
+
CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
ADD_INSNL(body_seq, node, jump, endlabel);
@@ -6671,10 +6691,12 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
node = RNODE_WHEN(node)->nd_next;
}
/* else */
+ const NODE *const coverage_node = node ? node : orig_node;
add_trace_branch_coverage(
iseq,
ret,
- node ? node : orig_node,
+ nd_code_loc(coverage_node),
+ nd_node_id(coverage_node),
branch_id,
"else",
branches);
@@ -7613,7 +7635,7 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
INIT_ANCHOR(body_seq);
INIT_ANCHOR(cond_seq);
- branches = decl_branch_base(iseq, node, "case");
+ branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
node = RNODE_CASE3(node)->nd_body;
EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
@@ -7647,13 +7669,17 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
l1 = NEW_LABEL(line);
ADD_LABEL(body_seq, l1);
ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
+
+ const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
add_trace_branch_coverage(
iseq,
body_seq,
- RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node,
+ nd_code_loc(coverage_node),
+ nd_node_id(coverage_node),
branch_id++,
"in",
branches);
+
CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
ADD_INSNL(body_seq, line_node, jump, endlabel);
@@ -7685,7 +7711,7 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
ADD_LABEL(cond_seq, elselabel);
ADD_INSN(cond_seq, line_node, pop);
ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
- add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
+ add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
CHECK(COMPILE_(cond_seq, "else", node, popped));
ADD_INSNL(cond_seq, line_node, jump, endlabel);
ADD_INSN(cond_seq, line_node, putnil);
@@ -7696,7 +7722,7 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
else {
debugs("== else (implicit)\n");
ADD_LABEL(cond_seq, elselabel);
- add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
+ add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
if (single_pattern) {
@@ -7813,14 +7839,18 @@ compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
if (tmp_label) ADD_LABEL(ret, tmp_label);
ADD_LABEL(ret, redo_label);
- branches = decl_branch_base(iseq, node, type == NODE_WHILE ? "while" : "until");
+ branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
+
+ const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
add_trace_branch_coverage(
iseq,
ret,
- RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node,
+ nd_code_loc(coverage_node),
+ nd_node_id(coverage_node),
0,
"body",
branches);
+
CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
ADD_LABEL(ret, next_label); /* next */
@@ -8428,11 +8458,11 @@ qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, co
LABEL *else_label = NEW_LABEL(nd_line(line_node));
VALUE br = 0;
- br = decl_branch_base(iseq, node, "&.");
+ br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
*branches = br;
ADD_INSN(recv, line_node, dup);
ADD_INSNL(recv, line_node, branchnil, else_label);
- add_trace_branch_coverage(iseq, recv, node, 0, "then", br);
+ add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
return else_label;
}
@@ -8444,7 +8474,7 @@ qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VAL
end_label = NEW_LABEL(nd_line(line_node));
ADD_INSNL(ret, line_node, jump, end_label);
ADD_LABEL(ret, else_label);
- add_trace_branch_coverage(iseq, ret, node, 1, "else", branches);
+ add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
ADD_LABEL(ret, end_label);
}
@@ -8750,15 +8780,10 @@ compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const N
scope_node.nd_body = mandatory_node(iseq, node);
scope_node.nd_args = &args_node;
- rb_ast_body_t ast = {
- .root = RNODE(&scope_node),
- .frozen_string_literal = -1,
- .coverage_enabled = -1,
- .script_lines = NULL
- };
+ VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
ISEQ_BODY(iseq)->mandatory_only_iseq =
- rb_iseq_new_with_opt(&ast, rb_iseq_base_label(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,
@@ -14211,6 +14236,8 @@ ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes,
static void
ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
{
+ StringValue(str);
+
if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
rb_raise(rb_eRuntimeError, "broken binary format");
}
diff --git a/configure.ac b/configure.ac
index 9ea0013850..e9a452ebee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -427,15 +427,22 @@ AS_CASE(["$build_os"],
# default spec.
# Xcode linker warns for deprecated architecture and wrongly
# installed TBD files.
- CC_WRAPPER="" CC_NO_WRAPPER="$CC"
+ AC_MSG_CHECKING(for $CC linker warning)
+ suppress_ld_waring=no
echo 'int main(void) {return 0;}' > conftest.c
- AS_IF([$CC -framework Foundation -o conftest conftest.c 2>&1 |
- grep -e '^ld: warning: ignoring duplicate libraries:' \
- -e '^ld: warning: text-based stub file' >/dev/null], [
- CC_WRAPPER=`cd -P "${tooldir}" && pwd`/darwin-cc
- CC="$CC_WRAPPER $CC"
+ AS_IF([$CC -framework Foundation -o conftest -ggdb3 conftest.c 2>&1 |
+ grep \
+ -e '^ld: warning: ignoring duplicate libraries:' \
+ -e '^ld: warning: text-based stub file' \
+ -e '^ld: warning: -multiply_defined is obsolete' \
+ -e "^warning: '\.debug_macinfo'" \
+ -e '^note: while processing' \
+ >/dev/null], [
+ suppress_ld_waring=yes
])
rm -fr conftest*
+ test $suppress_ld_waring = yes && warnflags="${warnflags:+${warnflags} }-Wl,-w"
+ AC_MSG_RESULT($suppress_ld_waring)
])
AS_CASE(["$target_os"],
[wasi*], [
@@ -1360,6 +1367,7 @@ AC_CHECK_HEADERS(ucontext.h)
AC_CHECK_HEADERS(utime.h)
AC_CHECK_HEADERS(sys/epoll.h)
AC_CHECK_HEADERS(sys/event.h)
+AC_CHECK_HEADERS(stdckdint.h)
AS_CASE("$target_cpu", [x64|x86_64|i[3-6]86*], [
AC_CHECK_HEADERS(x86intrin.h)
@@ -1768,7 +1776,7 @@ AC_CACHE_CHECK(for function name string predefined identifier,
[AS_CASE(["$target_os"],[openbsd*],[
rb_cv_function_name_string=__func__
],[
- rb_cv_function_name_string=no
+ rb_cv_function_name_string=no
RUBY_WERROR_FLAG([
for func in __func__ __FUNCTION__; do
AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include <stdio.h>]],
@@ -1776,7 +1784,8 @@ AC_CACHE_CHECK(for function name string predefined identifier,
[rb_cv_function_name_string=$func
break])
done
- ])])]
+ ])
+ ])]
)
AS_IF([test "$rb_cv_function_name_string" != no], [
AC_DEFINE_UNQUOTED(RUBY_FUNCTION_NAME_STRING, [$rb_cv_function_name_string])
diff --git a/cont.c b/cont.c
index 2cbabba489..8f222dfef8 100644
--- a/cont.c
+++ b/cont.c
@@ -2569,11 +2569,10 @@ rb_fiber_start(rb_fiber_t *fiber)
void
rb_threadptr_root_fiber_setup(rb_thread_t *th)
{
- rb_fiber_t *fiber = ruby_mimmalloc(sizeof(rb_fiber_t));
+ rb_fiber_t *fiber = ruby_mimcalloc(1, sizeof(rb_fiber_t));
if (!fiber) {
rb_bug("%s", strerror(errno)); /* ... is it possible to call rb_bug here? */
}
- MEMZERO(fiber, rb_fiber_t, 1);
fiber->cont.type = FIBER_CONTEXT;
fiber->cont.saved_ec.fiber_ptr = fiber;
fiber->cont.saved_ec.thread_ptr = th;
diff --git a/defs/gmake.mk b/defs/gmake.mk
index e502b9f83e..c914b39690 100644
--- a/defs/gmake.mk
+++ b/defs/gmake.mk
@@ -513,10 +513,12 @@ ifneq ($(POSTLINK),)
endif
$(Q) $(RMALL) $@.*
-rubyspec-capiext: $(patsubst %.c,$(RUBYSPEC_CAPIEXT)/%.$(DLEXT),$(notdir $(wildcard $(srcdir)/$(RUBYSPEC_CAPIEXT)/*.c)))
+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
diff --git a/dln.c b/dln.c
index 3e08728a6b..89f16b54f0 100644
--- a/dln.c
+++ b/dln.c
@@ -76,6 +76,12 @@ void *xrealloc();
# include <unistd.h>
#endif
+bool
+dln_supported_p(void)
+{
+ return true;
+}
+
#ifndef dln_loaderror
static void
dln_loaderror(const char *format, ...)
@@ -194,7 +200,6 @@ dln_strerror(char *message, size_t size)
}
return message;
}
-#define dln_strerror() dln_strerror(message, sizeof message)
#elif defined USE_DLN_DLOPEN
static const char *
dln_strerror(void)
@@ -340,15 +345,12 @@ dln_disable_dlclose(void)
#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
void *
-dln_open(const char *file)
+dln_open(const char *file, char *error, size_t size)
{
static const char incompatible[] = "incompatible library version";
- const char *error = NULL;
void *handle;
#if defined(_WIN32)
- char message[1024];
-
/* Convert the file path to wide char */
WCHAR *winfile = rb_w32_mbstr_to_wstr(CP_UTF8, file, -1, NULL);
if (!winfile) {
@@ -360,15 +362,15 @@ dln_open(const char *file)
free(winfile);
if (!handle) {
- error = dln_strerror();
- goto failed;
+ strlcpy(error, dln_strerror(error, size), size);
+ return NULL;
}
# if defined(RUBY_EXPORT)
if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
FreeLibrary(handle);
- error = incompatible;
- goto failed;
+ strlcpy(error, incompatible, size);
+ return NULL;
}
# endif
@@ -387,8 +389,8 @@ dln_open(const char *file)
/* Load file */
handle = dlopen(file, RTLD_LAZY|RTLD_GLOBAL);
if (handle == NULL) {
- error = dln_strerror();
- goto failed;
+ strlcpy(error, dln_strerror(), size);
+ return NULL;
}
# if defined(RUBY_EXPORT)
@@ -410,11 +412,15 @@ dln_open(const char *file)
libruby_name = tmp;
}
dlclose(handle);
+
if (libruby_name) {
- dln_loaderror("linked to incompatible %s - %s", libruby_name, file);
+ snprintf(error, size, "linked to incompatible %s - %s", libruby_name, file);
+ }
+ else {
+ strlcpy(error, incompatible, size);
}
- error = incompatible;
- goto failed;
+
+ return NULL;
}
}
}
@@ -422,9 +428,6 @@ dln_open(const char *file)
#endif
return handle;
-
- failed:
- dln_loaderror("%s - %s", error, file);
}
void *
@@ -446,7 +449,7 @@ dln_sym_func(void *handle, const char *symbol)
const char *error;
#if defined(_WIN32)
char message[1024];
- error = dln_strerror();
+ error = dln_strerror(message, sizeof(message));
#elif defined(USE_DLN_DLOPEN)
const size_t errlen = strlen(error = dln_strerror()) + 1;
error = memcpy(ALLOCA_N(char, errlen), error, errlen);
@@ -501,7 +504,12 @@ void *
dln_load(const char *file)
{
#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
- void *handle = dln_open(file);
+ char error[1024];
+ void *handle = dln_open(file, error, sizeof(error));
+
+ if (handle == NULL) {
+ dln_loaderror("%s - %s", error, file);
+ }
#ifdef RUBY_DLN_CHECK_ABI
typedef unsigned long long abi_version_number;
diff --git a/dln.h b/dln.h
index 13eef58d9f..26df5266f7 100644
--- a/dln.h
+++ b/dln.h
@@ -22,10 +22,11 @@ RUBY_SYMBOL_EXPORT_BEGIN
#define DLN_FIND_EXTRA_ARG_DECL
#endif
+bool dln_supported_p(void);
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_open(const char *file);
+void *dln_open(const char *file, char *error, size_t size);
void *dln_symbol(void*,const char*);
RUBY_SYMBOL_EXPORT_END
diff --git a/dmydln.c b/dmydln.c
index 22f40e82eb..1f5b59022b 100644
--- a/dmydln.c
+++ b/dmydln.c
@@ -3,6 +3,12 @@
#include "ruby/ruby.h"
+bool
+dln_supported_p(void)
+{
+ return false;
+}
+
NORETURN(void *dln_load(const char *));
void*
dln_load(const char *file)
@@ -21,12 +27,11 @@ dln_symbol(void *handle, const char *symbol)
UNREACHABLE_RETURN(NULL);
}
-NORETURN(void *dln_open(const char*));
void*
-dln_open(const char *library)
+dln_open(const char *library, char *error, size_t size)
{
- rb_loaderror("this executable file can't load extension libraries");
-
- UNREACHABLE_RETURN(NULL);
+ static const char *error_str = "this executable file can't load extension libraries";
+ strlcpy(error, error_str, size);
+ return NULL;
}
diff --git a/doc/contributing/building_ruby.md b/doc/contributing/building_ruby.md
index 4dabaca840..38c78e3cca 100644
--- a/doc/contributing/building_ruby.md
+++ b/doc/contributing/building_ruby.md
@@ -89,8 +89,6 @@
../configure --prefix="${HOME}/.rubies/ruby-master"
```
- - If you are frequently building Ruby, add the `--disable-install-doc` flag to not build documentation which will speed up the build process.
-
- Also `-C` (or `--config-cache`) would reduce time to configure from the next time.
5. Build Ruby:
@@ -187,7 +185,7 @@ Using the address sanitizer (ASAN) is a great way to detect memory issues. It ca
``` shell
./autogen.sh
mkdir build && cd build
-../configure CC=clang cflags="-fsanitize=address -fno-omit-frame-pointer -DUSE_MN_THREADS=0" # and any other options you might like
+../configure CC=clang-18 cflags="-fsanitize=address -fno-omit-frame-pointer -DUSE_MN_THREADS=0" # and any other options you might like
make
```
The compiled Ruby will now automatically crash with a report and a backtrace if ASAN detects a memory safety issue. To run Ruby's test suite under ASAN, issue the following command. Note that this will take quite a long time (over two hours on my laptop); the `RUBY_TEST_TIMEOUT_SCALE` and `SYNTAX_SUGEST_TIMEOUT` variables are required to make sure tests don't spuriously fail with timeouts when in fact they're just slow.
@@ -200,7 +198,7 @@ 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 [9d0a5148ae062a0481a4a18fbeb9cfd01dc10428](https://bugs.ruby-lang.org/projects/ruby-master/repository/git/revisions/9d0a5148ae062a0481a4a18fbeb9cfd01dc10428))
* Due to [this bug](https://bugs.ruby-lang.org/issues/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` configure argument).
-* Currently, ASAN will only work correctly when using a recent head build of LLVM/Clang - it requires [this bugfix](https://github.com/llvm/llvm-project/pull/75290) related to multithreaded `fork`, which is not yet in any released version. See [here](https://llvm.org/docs/CMake.html) for instructions on how to build LLVM/Clang from source (note you will need at least the `clang` and `compiler-rt` projects enabled). Then, you will need to replace `CC=clang` in the instructions with an explicit path to your built Clang binary.
+* ASAN will only work when using Clang version 18 or later - it requires [this bugfix](https://github.com/llvm/llvm-project/pull/75290) related to multithreaded `fork`.
* ASAN has only been tested so far with Clang on Linux. It may or may not work with other compilers or on other platforms - please file an issue on [https://bugs.ruby-lang.org](https://bugs.ruby-lang.org) if you run into problems with such configurations (or, to report that they actually work properly!)
* In particular, although I have not yet tried it, I have reason to believe ASAN will _not_ work properly on macOS yet - the fix for the multithreaded fork issue was actually reverted for macOS (see [here](https://github.com/llvm/llvm-project/commit/2a03854e4ce9bb1bcd79a211063bc63c4657f92c)). Please open an issue on [https://bugs.ruby-lang.org](https://bugs.ruby-lang.org) if this is a problem for you.
diff --git a/doc/encodings.rdoc b/doc/encodings.rdoc
index 97c0d22616..d85099cdbc 100644
--- a/doc/encodings.rdoc
+++ b/doc/encodings.rdoc
@@ -419,7 +419,7 @@ These keyword-value pairs specify encoding options:
hash = {"\u3042" => 'xyzzy'}
hash.default = 'XYZZY'
- s.encode('ASCII', fallback: h) # => "xyzzyfooXYZZY"
+ s.encode('ASCII', fallback: hash) # => "xyzzyfooXYZZY"
def (fallback = "U+%.4X").escape(x)
self % x.unpack("U")
diff --git a/doc/extension.ja.rdoc b/doc/extension.ja.rdoc
index 48699ac620..2f7856f3d4 100644
--- a/doc/extension.ja.rdoc
+++ b/doc/extension.ja.rdoc
@@ -784,6 +784,11 @@ RUBY_TYPED_WB_PROTECTED ::
GC}[rdoc-ref:@Appendix+D.+-E4-B8-96-E4-BB-A3-E5-88-A5GC]
も参照してください.
+このマクロは例外を発生させる可能性があることに注意してくださ
+い. ラップされる sval が,解放する必要があるリソース (割り
+当てられたメモリ,外部ライブラリからのハンドルなど) を保持し
+ている場合は,rb_protect を使用する必要があります.
+
Cの構造体の割当と対応するオブジェクトの生成を同時に行うマク
ロとして以下のものが提供されています.
diff --git a/doc/extension.rdoc b/doc/extension.rdoc
index 01ac140e69..ba59d107ab 100644
--- a/doc/extension.rdoc
+++ b/doc/extension.rdoc
@@ -759,7 +759,12 @@ RUBY_TYPED_FROZEN_SHAREABLE ::
If this flag is not set, the object can not become a shareable
object by Ractor.make_shareable() method.
-You can allocate and wrap the structure in one step.
+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.
+
+You can allocate and wrap the structure in one step, in more
+preferable manner.
TypedData_Make_Struct(klass, type, data_type, sval)
@@ -768,6 +773,10 @@ the structure, which is also allocated. This macro works like:
(sval = ZALLOC(type), TypedData_Wrap_Struct(klass, data_type, sval))
+However, you should use this macro instead of "allocation then wrap"
+like the above code if it is simply allocated, because the latter can
+raise a NoMemoryError and sval will be memory leaked in that case.
+
Arguments klass and data_type work like their counterparts in
TypedData_Wrap_Struct(). A pointer to the allocated structure will
be assigned to sval, which should be a pointer of the type specified.
diff --git a/doc/globals.rdoc b/doc/globals.rdoc
index 1bf78a60ab..1b51bb1b36 100644
--- a/doc/globals.rdoc
+++ b/doc/globals.rdoc
@@ -1,7 +1,7 @@
= Pre-Defined Global Variables
Some of the pre-defined global variables have synonyms
-that are available via module Engish.
+that are available via module English.
For each of those, the \English synonym is given.
To use the module:
diff --git a/doc/syntax/pattern_matching.rdoc b/doc/syntax/pattern_matching.rdoc
index e49c09a1f8..6a30380f46 100644
--- a/doc/syntax/pattern_matching.rdoc
+++ b/doc/syntax/pattern_matching.rdoc
@@ -422,7 +422,8 @@ These core and library classes implement deconstruction:
== Guard clauses
-+if+ can be used to attach an additional condition (guard clause) when the pattern matches. This condition may use bound variables:
++if+ can be used to attach an additional condition (guard clause) when the pattern matches in +case+/+in+ expressions.
+This condition may use bound variables:
case [1, 2]
in a, b if b == a*2
@@ -450,6 +451,11 @@ These core and library classes implement deconstruction:
end
#=> "matched"
+Note that <code>=></code> and +in+ operator can not have a guard clause.
+The following examples is parsed as a standalone expression with modifier +if+.
+
+ [1, 2] in a, b if b == a*2
+
== Appendix A. Pattern syntax
Approximate syntax is:
diff --git a/enc/depend b/enc/depend
index 128203d5ec..2918a90a05 100644
--- a/enc/depend
+++ b/enc/depend
@@ -336,6 +336,7 @@ enc/ascii.$(OBJEXT): internal/special_consts.h
enc/ascii.$(OBJEXT): internal/static_assert.h
enc/ascii.$(OBJEXT): internal/stdalign.h
enc/ascii.$(OBJEXT): internal/stdbool.h
+enc/ascii.$(OBJEXT): internal/stdckdint.h
enc/ascii.$(OBJEXT): internal/symbol.h
enc/ascii.$(OBJEXT): internal/value.h
enc/ascii.$(OBJEXT): internal/value_type.h
@@ -497,6 +498,7 @@ enc/big5.$(OBJEXT): internal/special_consts.h
enc/big5.$(OBJEXT): internal/static_assert.h
enc/big5.$(OBJEXT): internal/stdalign.h
enc/big5.$(OBJEXT): internal/stdbool.h
+enc/big5.$(OBJEXT): internal/stdckdint.h
enc/big5.$(OBJEXT): internal/symbol.h
enc/big5.$(OBJEXT): internal/value.h
enc/big5.$(OBJEXT): internal/value_type.h
@@ -668,6 +670,7 @@ enc/cesu_8.$(OBJEXT): internal/special_consts.h
enc/cesu_8.$(OBJEXT): internal/static_assert.h
enc/cesu_8.$(OBJEXT): internal/stdalign.h
enc/cesu_8.$(OBJEXT): internal/stdbool.h
+enc/cesu_8.$(OBJEXT): internal/stdckdint.h
enc/cesu_8.$(OBJEXT): internal/symbol.h
enc/cesu_8.$(OBJEXT): internal/value.h
enc/cesu_8.$(OBJEXT): internal/value_type.h
@@ -829,6 +832,7 @@ enc/cp949.$(OBJEXT): internal/special_consts.h
enc/cp949.$(OBJEXT): internal/static_assert.h
enc/cp949.$(OBJEXT): internal/stdalign.h
enc/cp949.$(OBJEXT): internal/stdbool.h
+enc/cp949.$(OBJEXT): internal/stdckdint.h
enc/cp949.$(OBJEXT): internal/symbol.h
enc/cp949.$(OBJEXT): internal/value.h
enc/cp949.$(OBJEXT): internal/value_type.h
@@ -989,6 +993,7 @@ enc/emacs_mule.$(OBJEXT): internal/special_consts.h
enc/emacs_mule.$(OBJEXT): internal/static_assert.h
enc/emacs_mule.$(OBJEXT): internal/stdalign.h
enc/emacs_mule.$(OBJEXT): internal/stdbool.h
+enc/emacs_mule.$(OBJEXT): internal/stdckdint.h
enc/emacs_mule.$(OBJEXT): internal/symbol.h
enc/emacs_mule.$(OBJEXT): internal/value.h
enc/emacs_mule.$(OBJEXT): internal/value_type.h
@@ -1159,6 +1164,7 @@ enc/encdb.$(OBJEXT): internal/special_consts.h
enc/encdb.$(OBJEXT): internal/static_assert.h
enc/encdb.$(OBJEXT): internal/stdalign.h
enc/encdb.$(OBJEXT): internal/stdbool.h
+enc/encdb.$(OBJEXT): internal/stdckdint.h
enc/encdb.$(OBJEXT): internal/symbol.h
enc/encdb.$(OBJEXT): internal/value.h
enc/encdb.$(OBJEXT): internal/value_type.h
@@ -1322,6 +1328,7 @@ enc/euc_jp.$(OBJEXT): internal/special_consts.h
enc/euc_jp.$(OBJEXT): internal/static_assert.h
enc/euc_jp.$(OBJEXT): internal/stdalign.h
enc/euc_jp.$(OBJEXT): internal/stdbool.h
+enc/euc_jp.$(OBJEXT): internal/stdckdint.h
enc/euc_jp.$(OBJEXT): internal/symbol.h
enc/euc_jp.$(OBJEXT): internal/value.h
enc/euc_jp.$(OBJEXT): internal/value_type.h
@@ -1482,6 +1489,7 @@ enc/euc_kr.$(OBJEXT): internal/special_consts.h
enc/euc_kr.$(OBJEXT): internal/static_assert.h
enc/euc_kr.$(OBJEXT): internal/stdalign.h
enc/euc_kr.$(OBJEXT): internal/stdbool.h
+enc/euc_kr.$(OBJEXT): internal/stdckdint.h
enc/euc_kr.$(OBJEXT): internal/symbol.h
enc/euc_kr.$(OBJEXT): internal/value.h
enc/euc_kr.$(OBJEXT): internal/value_type.h
@@ -1642,6 +1650,7 @@ enc/euc_tw.$(OBJEXT): internal/special_consts.h
enc/euc_tw.$(OBJEXT): internal/static_assert.h
enc/euc_tw.$(OBJEXT): internal/stdalign.h
enc/euc_tw.$(OBJEXT): internal/stdbool.h
+enc/euc_tw.$(OBJEXT): internal/stdckdint.h
enc/euc_tw.$(OBJEXT): internal/symbol.h
enc/euc_tw.$(OBJEXT): internal/value.h
enc/euc_tw.$(OBJEXT): internal/value_type.h
@@ -1802,6 +1811,7 @@ enc/gb18030.$(OBJEXT): internal/special_consts.h
enc/gb18030.$(OBJEXT): internal/static_assert.h
enc/gb18030.$(OBJEXT): internal/stdalign.h
enc/gb18030.$(OBJEXT): internal/stdbool.h
+enc/gb18030.$(OBJEXT): internal/stdckdint.h
enc/gb18030.$(OBJEXT): internal/symbol.h
enc/gb18030.$(OBJEXT): internal/value.h
enc/gb18030.$(OBJEXT): internal/value_type.h
@@ -1962,6 +1972,7 @@ enc/gb2312.$(OBJEXT): internal/special_consts.h
enc/gb2312.$(OBJEXT): internal/static_assert.h
enc/gb2312.$(OBJEXT): internal/stdalign.h
enc/gb2312.$(OBJEXT): internal/stdbool.h
+enc/gb2312.$(OBJEXT): internal/stdckdint.h
enc/gb2312.$(OBJEXT): internal/symbol.h
enc/gb2312.$(OBJEXT): internal/value.h
enc/gb2312.$(OBJEXT): internal/value_type.h
@@ -2122,6 +2133,7 @@ enc/gbk.$(OBJEXT): internal/special_consts.h
enc/gbk.$(OBJEXT): internal/static_assert.h
enc/gbk.$(OBJEXT): internal/stdalign.h
enc/gbk.$(OBJEXT): internal/stdbool.h
+enc/gbk.$(OBJEXT): internal/stdckdint.h
enc/gbk.$(OBJEXT): internal/symbol.h
enc/gbk.$(OBJEXT): internal/value.h
enc/gbk.$(OBJEXT): internal/value_type.h
@@ -2283,6 +2295,7 @@ enc/iso_8859_1.$(OBJEXT): internal/special_consts.h
enc/iso_8859_1.$(OBJEXT): internal/static_assert.h
enc/iso_8859_1.$(OBJEXT): internal/stdalign.h
enc/iso_8859_1.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_1.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_1.$(OBJEXT): internal/symbol.h
enc/iso_8859_1.$(OBJEXT): internal/value.h
enc/iso_8859_1.$(OBJEXT): internal/value_type.h
@@ -2444,6 +2457,7 @@ enc/iso_8859_10.$(OBJEXT): internal/special_consts.h
enc/iso_8859_10.$(OBJEXT): internal/static_assert.h
enc/iso_8859_10.$(OBJEXT): internal/stdalign.h
enc/iso_8859_10.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_10.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_10.$(OBJEXT): internal/symbol.h
enc/iso_8859_10.$(OBJEXT): internal/value.h
enc/iso_8859_10.$(OBJEXT): internal/value_type.h
@@ -2604,6 +2618,7 @@ enc/iso_8859_11.$(OBJEXT): internal/special_consts.h
enc/iso_8859_11.$(OBJEXT): internal/static_assert.h
enc/iso_8859_11.$(OBJEXT): internal/stdalign.h
enc/iso_8859_11.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_11.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_11.$(OBJEXT): internal/symbol.h
enc/iso_8859_11.$(OBJEXT): internal/value.h
enc/iso_8859_11.$(OBJEXT): internal/value_type.h
@@ -2765,6 +2780,7 @@ enc/iso_8859_13.$(OBJEXT): internal/special_consts.h
enc/iso_8859_13.$(OBJEXT): internal/static_assert.h
enc/iso_8859_13.$(OBJEXT): internal/stdalign.h
enc/iso_8859_13.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_13.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_13.$(OBJEXT): internal/symbol.h
enc/iso_8859_13.$(OBJEXT): internal/value.h
enc/iso_8859_13.$(OBJEXT): internal/value_type.h
@@ -2926,6 +2942,7 @@ enc/iso_8859_14.$(OBJEXT): internal/special_consts.h
enc/iso_8859_14.$(OBJEXT): internal/static_assert.h
enc/iso_8859_14.$(OBJEXT): internal/stdalign.h
enc/iso_8859_14.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_14.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_14.$(OBJEXT): internal/symbol.h
enc/iso_8859_14.$(OBJEXT): internal/value.h
enc/iso_8859_14.$(OBJEXT): internal/value_type.h
@@ -3087,6 +3104,7 @@ enc/iso_8859_15.$(OBJEXT): internal/special_consts.h
enc/iso_8859_15.$(OBJEXT): internal/static_assert.h
enc/iso_8859_15.$(OBJEXT): internal/stdalign.h
enc/iso_8859_15.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_15.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_15.$(OBJEXT): internal/symbol.h
enc/iso_8859_15.$(OBJEXT): internal/value.h
enc/iso_8859_15.$(OBJEXT): internal/value_type.h
@@ -3248,6 +3266,7 @@ enc/iso_8859_16.$(OBJEXT): internal/special_consts.h
enc/iso_8859_16.$(OBJEXT): internal/static_assert.h
enc/iso_8859_16.$(OBJEXT): internal/stdalign.h
enc/iso_8859_16.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_16.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_16.$(OBJEXT): internal/symbol.h
enc/iso_8859_16.$(OBJEXT): internal/value.h
enc/iso_8859_16.$(OBJEXT): internal/value_type.h
@@ -3409,6 +3428,7 @@ enc/iso_8859_2.$(OBJEXT): internal/special_consts.h
enc/iso_8859_2.$(OBJEXT): internal/static_assert.h
enc/iso_8859_2.$(OBJEXT): internal/stdalign.h
enc/iso_8859_2.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_2.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_2.$(OBJEXT): internal/symbol.h
enc/iso_8859_2.$(OBJEXT): internal/value.h
enc/iso_8859_2.$(OBJEXT): internal/value_type.h
@@ -3570,6 +3590,7 @@ enc/iso_8859_3.$(OBJEXT): internal/special_consts.h
enc/iso_8859_3.$(OBJEXT): internal/static_assert.h
enc/iso_8859_3.$(OBJEXT): internal/stdalign.h
enc/iso_8859_3.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_3.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_3.$(OBJEXT): internal/symbol.h
enc/iso_8859_3.$(OBJEXT): internal/value.h
enc/iso_8859_3.$(OBJEXT): internal/value_type.h
@@ -3731,6 +3752,7 @@ enc/iso_8859_4.$(OBJEXT): internal/special_consts.h
enc/iso_8859_4.$(OBJEXT): internal/static_assert.h
enc/iso_8859_4.$(OBJEXT): internal/stdalign.h
enc/iso_8859_4.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_4.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_4.$(OBJEXT): internal/symbol.h
enc/iso_8859_4.$(OBJEXT): internal/value.h
enc/iso_8859_4.$(OBJEXT): internal/value_type.h
@@ -3891,6 +3913,7 @@ enc/iso_8859_5.$(OBJEXT): internal/special_consts.h
enc/iso_8859_5.$(OBJEXT): internal/static_assert.h
enc/iso_8859_5.$(OBJEXT): internal/stdalign.h
enc/iso_8859_5.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_5.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_5.$(OBJEXT): internal/symbol.h
enc/iso_8859_5.$(OBJEXT): internal/value.h
enc/iso_8859_5.$(OBJEXT): internal/value_type.h
@@ -4051,6 +4074,7 @@ enc/iso_8859_6.$(OBJEXT): internal/special_consts.h
enc/iso_8859_6.$(OBJEXT): internal/static_assert.h
enc/iso_8859_6.$(OBJEXT): internal/stdalign.h
enc/iso_8859_6.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_6.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_6.$(OBJEXT): internal/symbol.h
enc/iso_8859_6.$(OBJEXT): internal/value.h
enc/iso_8859_6.$(OBJEXT): internal/value_type.h
@@ -4211,6 +4235,7 @@ enc/iso_8859_7.$(OBJEXT): internal/special_consts.h
enc/iso_8859_7.$(OBJEXT): internal/static_assert.h
enc/iso_8859_7.$(OBJEXT): internal/stdalign.h
enc/iso_8859_7.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_7.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_7.$(OBJEXT): internal/symbol.h
enc/iso_8859_7.$(OBJEXT): internal/value.h
enc/iso_8859_7.$(OBJEXT): internal/value_type.h
@@ -4371,6 +4396,7 @@ enc/iso_8859_8.$(OBJEXT): internal/special_consts.h
enc/iso_8859_8.$(OBJEXT): internal/static_assert.h
enc/iso_8859_8.$(OBJEXT): internal/stdalign.h
enc/iso_8859_8.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_8.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_8.$(OBJEXT): internal/symbol.h
enc/iso_8859_8.$(OBJEXT): internal/value.h
enc/iso_8859_8.$(OBJEXT): internal/value_type.h
@@ -4532,6 +4558,7 @@ enc/iso_8859_9.$(OBJEXT): internal/special_consts.h
enc/iso_8859_9.$(OBJEXT): internal/static_assert.h
enc/iso_8859_9.$(OBJEXT): internal/stdalign.h
enc/iso_8859_9.$(OBJEXT): internal/stdbool.h
+enc/iso_8859_9.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_9.$(OBJEXT): internal/symbol.h
enc/iso_8859_9.$(OBJEXT): internal/value.h
enc/iso_8859_9.$(OBJEXT): internal/value_type.h
@@ -4692,6 +4719,7 @@ enc/koi8_r.$(OBJEXT): internal/special_consts.h
enc/koi8_r.$(OBJEXT): internal/static_assert.h
enc/koi8_r.$(OBJEXT): internal/stdalign.h
enc/koi8_r.$(OBJEXT): internal/stdbool.h
+enc/koi8_r.$(OBJEXT): internal/stdckdint.h
enc/koi8_r.$(OBJEXT): internal/symbol.h
enc/koi8_r.$(OBJEXT): internal/value.h
enc/koi8_r.$(OBJEXT): internal/value_type.h
@@ -4852,6 +4880,7 @@ enc/koi8_u.$(OBJEXT): internal/special_consts.h
enc/koi8_u.$(OBJEXT): internal/static_assert.h
enc/koi8_u.$(OBJEXT): internal/stdalign.h
enc/koi8_u.$(OBJEXT): internal/stdbool.h
+enc/koi8_u.$(OBJEXT): internal/stdckdint.h
enc/koi8_u.$(OBJEXT): internal/symbol.h
enc/koi8_u.$(OBJEXT): internal/value.h
enc/koi8_u.$(OBJEXT): internal/value_type.h
@@ -5015,6 +5044,7 @@ enc/shift_jis.$(OBJEXT): internal/special_consts.h
enc/shift_jis.$(OBJEXT): internal/static_assert.h
enc/shift_jis.$(OBJEXT): internal/stdalign.h
enc/shift_jis.$(OBJEXT): internal/stdbool.h
+enc/shift_jis.$(OBJEXT): internal/stdckdint.h
enc/shift_jis.$(OBJEXT): internal/symbol.h
enc/shift_jis.$(OBJEXT): internal/value.h
enc/shift_jis.$(OBJEXT): internal/value_type.h
@@ -5174,6 +5204,7 @@ enc/trans/big5.$(OBJEXT): internal/special_consts.h
enc/trans/big5.$(OBJEXT): internal/static_assert.h
enc/trans/big5.$(OBJEXT): internal/stdalign.h
enc/trans/big5.$(OBJEXT): internal/stdbool.h
+enc/trans/big5.$(OBJEXT): internal/stdckdint.h
enc/trans/big5.$(OBJEXT): internal/symbol.h
enc/trans/big5.$(OBJEXT): internal/value.h
enc/trans/big5.$(OBJEXT): internal/value_type.h
@@ -5332,6 +5363,7 @@ enc/trans/cesu_8.$(OBJEXT): internal/special_consts.h
enc/trans/cesu_8.$(OBJEXT): internal/static_assert.h
enc/trans/cesu_8.$(OBJEXT): internal/stdalign.h
enc/trans/cesu_8.$(OBJEXT): internal/stdbool.h
+enc/trans/cesu_8.$(OBJEXT): internal/stdckdint.h
enc/trans/cesu_8.$(OBJEXT): internal/symbol.h
enc/trans/cesu_8.$(OBJEXT): internal/value.h
enc/trans/cesu_8.$(OBJEXT): internal/value_type.h
@@ -5490,6 +5522,7 @@ enc/trans/chinese.$(OBJEXT): internal/special_consts.h
enc/trans/chinese.$(OBJEXT): internal/static_assert.h
enc/trans/chinese.$(OBJEXT): internal/stdalign.h
enc/trans/chinese.$(OBJEXT): internal/stdbool.h
+enc/trans/chinese.$(OBJEXT): internal/stdckdint.h
enc/trans/chinese.$(OBJEXT): internal/symbol.h
enc/trans/chinese.$(OBJEXT): internal/value.h
enc/trans/chinese.$(OBJEXT): internal/value_type.h
@@ -5648,6 +5681,7 @@ enc/trans/ebcdic.$(OBJEXT): internal/special_consts.h
enc/trans/ebcdic.$(OBJEXT): internal/static_assert.h
enc/trans/ebcdic.$(OBJEXT): internal/stdalign.h
enc/trans/ebcdic.$(OBJEXT): internal/stdbool.h
+enc/trans/ebcdic.$(OBJEXT): internal/stdckdint.h
enc/trans/ebcdic.$(OBJEXT): internal/symbol.h
enc/trans/ebcdic.$(OBJEXT): internal/value.h
enc/trans/ebcdic.$(OBJEXT): internal/value_type.h
@@ -5806,6 +5840,7 @@ enc/trans/emoji.$(OBJEXT): internal/special_consts.h
enc/trans/emoji.$(OBJEXT): internal/static_assert.h
enc/trans/emoji.$(OBJEXT): internal/stdalign.h
enc/trans/emoji.$(OBJEXT): internal/stdbool.h
+enc/trans/emoji.$(OBJEXT): internal/stdckdint.h
enc/trans/emoji.$(OBJEXT): internal/symbol.h
enc/trans/emoji.$(OBJEXT): internal/value.h
enc/trans/emoji.$(OBJEXT): internal/value_type.h
@@ -5964,6 +5999,7 @@ enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/special_consts.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/static_assert.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/stdalign.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/stdbool.h
+enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/stdckdint.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/symbol.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/value.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/value_type.h
@@ -6122,6 +6158,7 @@ enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/special_consts.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/static_assert.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/stdalign.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/stdbool.h
+enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/stdckdint.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/symbol.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/value.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/value_type.h
@@ -6280,6 +6317,7 @@ enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/special_consts.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/static_assert.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/stdalign.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/stdbool.h
+enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/stdckdint.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/symbol.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/value.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/value_type.h
@@ -6438,6 +6476,7 @@ enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/special_consts.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/static_assert.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/stdalign.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/stdbool.h
+enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/stdckdint.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/symbol.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/value.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/value_type.h
@@ -6596,6 +6635,7 @@ enc/trans/escape.$(OBJEXT): internal/special_consts.h
enc/trans/escape.$(OBJEXT): internal/static_assert.h
enc/trans/escape.$(OBJEXT): internal/stdalign.h
enc/trans/escape.$(OBJEXT): internal/stdbool.h
+enc/trans/escape.$(OBJEXT): internal/stdckdint.h
enc/trans/escape.$(OBJEXT): internal/symbol.h
enc/trans/escape.$(OBJEXT): internal/value.h
enc/trans/escape.$(OBJEXT): internal/value_type.h
@@ -6754,6 +6794,7 @@ enc/trans/gb18030.$(OBJEXT): internal/special_consts.h
enc/trans/gb18030.$(OBJEXT): internal/static_assert.h
enc/trans/gb18030.$(OBJEXT): internal/stdalign.h
enc/trans/gb18030.$(OBJEXT): internal/stdbool.h
+enc/trans/gb18030.$(OBJEXT): internal/stdckdint.h
enc/trans/gb18030.$(OBJEXT): internal/symbol.h
enc/trans/gb18030.$(OBJEXT): internal/value.h
enc/trans/gb18030.$(OBJEXT): internal/value_type.h
@@ -6912,6 +6953,7 @@ enc/trans/gbk.$(OBJEXT): internal/special_consts.h
enc/trans/gbk.$(OBJEXT): internal/static_assert.h
enc/trans/gbk.$(OBJEXT): internal/stdalign.h
enc/trans/gbk.$(OBJEXT): internal/stdbool.h
+enc/trans/gbk.$(OBJEXT): internal/stdckdint.h
enc/trans/gbk.$(OBJEXT): internal/symbol.h
enc/trans/gbk.$(OBJEXT): internal/value.h
enc/trans/gbk.$(OBJEXT): internal/value_type.h
@@ -7070,6 +7112,7 @@ enc/trans/iso2022.$(OBJEXT): internal/special_consts.h
enc/trans/iso2022.$(OBJEXT): internal/static_assert.h
enc/trans/iso2022.$(OBJEXT): internal/stdalign.h
enc/trans/iso2022.$(OBJEXT): internal/stdbool.h
+enc/trans/iso2022.$(OBJEXT): internal/stdckdint.h
enc/trans/iso2022.$(OBJEXT): internal/symbol.h
enc/trans/iso2022.$(OBJEXT): internal/value.h
enc/trans/iso2022.$(OBJEXT): internal/value_type.h
@@ -7228,6 +7271,7 @@ enc/trans/japanese.$(OBJEXT): internal/special_consts.h
enc/trans/japanese.$(OBJEXT): internal/static_assert.h
enc/trans/japanese.$(OBJEXT): internal/stdalign.h
enc/trans/japanese.$(OBJEXT): internal/stdbool.h
+enc/trans/japanese.$(OBJEXT): internal/stdckdint.h
enc/trans/japanese.$(OBJEXT): internal/symbol.h
enc/trans/japanese.$(OBJEXT): internal/value.h
enc/trans/japanese.$(OBJEXT): internal/value_type.h
@@ -7386,6 +7430,7 @@ enc/trans/japanese_euc.$(OBJEXT): internal/special_consts.h
enc/trans/japanese_euc.$(OBJEXT): internal/static_assert.h
enc/trans/japanese_euc.$(OBJEXT): internal/stdalign.h
enc/trans/japanese_euc.$(OBJEXT): internal/stdbool.h
+enc/trans/japanese_euc.$(OBJEXT): internal/stdckdint.h
enc/trans/japanese_euc.$(OBJEXT): internal/symbol.h
enc/trans/japanese_euc.$(OBJEXT): internal/value.h
enc/trans/japanese_euc.$(OBJEXT): internal/value_type.h
@@ -7544,6 +7589,7 @@ enc/trans/japanese_sjis.$(OBJEXT): internal/special_consts.h
enc/trans/japanese_sjis.$(OBJEXT): internal/static_assert.h
enc/trans/japanese_sjis.$(OBJEXT): internal/stdalign.h
enc/trans/japanese_sjis.$(OBJEXT): internal/stdbool.h
+enc/trans/japanese_sjis.$(OBJEXT): internal/stdckdint.h
enc/trans/japanese_sjis.$(OBJEXT): internal/symbol.h
enc/trans/japanese_sjis.$(OBJEXT): internal/value.h
enc/trans/japanese_sjis.$(OBJEXT): internal/value_type.h
@@ -7702,6 +7748,7 @@ enc/trans/korean.$(OBJEXT): internal/special_consts.h
enc/trans/korean.$(OBJEXT): internal/static_assert.h
enc/trans/korean.$(OBJEXT): internal/stdalign.h
enc/trans/korean.$(OBJEXT): internal/stdbool.h
+enc/trans/korean.$(OBJEXT): internal/stdckdint.h
enc/trans/korean.$(OBJEXT): internal/symbol.h
enc/trans/korean.$(OBJEXT): internal/value.h
enc/trans/korean.$(OBJEXT): internal/value_type.h
@@ -7859,6 +7906,7 @@ enc/trans/newline.$(OBJEXT): internal/special_consts.h
enc/trans/newline.$(OBJEXT): internal/static_assert.h
enc/trans/newline.$(OBJEXT): internal/stdalign.h
enc/trans/newline.$(OBJEXT): internal/stdbool.h
+enc/trans/newline.$(OBJEXT): internal/stdckdint.h
enc/trans/newline.$(OBJEXT): internal/symbol.h
enc/trans/newline.$(OBJEXT): internal/value.h
enc/trans/newline.$(OBJEXT): internal/value_type.h
@@ -8017,6 +8065,7 @@ enc/trans/single_byte.$(OBJEXT): internal/special_consts.h
enc/trans/single_byte.$(OBJEXT): internal/static_assert.h
enc/trans/single_byte.$(OBJEXT): internal/stdalign.h
enc/trans/single_byte.$(OBJEXT): internal/stdbool.h
+enc/trans/single_byte.$(OBJEXT): internal/stdckdint.h
enc/trans/single_byte.$(OBJEXT): internal/symbol.h
enc/trans/single_byte.$(OBJEXT): internal/value.h
enc/trans/single_byte.$(OBJEXT): internal/value_type.h
@@ -8175,6 +8224,7 @@ enc/trans/transdb.$(OBJEXT): internal/special_consts.h
enc/trans/transdb.$(OBJEXT): internal/static_assert.h
enc/trans/transdb.$(OBJEXT): internal/stdalign.h
enc/trans/transdb.$(OBJEXT): internal/stdbool.h
+enc/trans/transdb.$(OBJEXT): internal/stdckdint.h
enc/trans/transdb.$(OBJEXT): internal/symbol.h
enc/trans/transdb.$(OBJEXT): internal/value.h
enc/trans/transdb.$(OBJEXT): internal/value_type.h
@@ -8334,6 +8384,7 @@ enc/trans/utf8_mac.$(OBJEXT): internal/special_consts.h
enc/trans/utf8_mac.$(OBJEXT): internal/static_assert.h
enc/trans/utf8_mac.$(OBJEXT): internal/stdalign.h
enc/trans/utf8_mac.$(OBJEXT): internal/stdbool.h
+enc/trans/utf8_mac.$(OBJEXT): internal/stdckdint.h
enc/trans/utf8_mac.$(OBJEXT): internal/symbol.h
enc/trans/utf8_mac.$(OBJEXT): internal/value.h
enc/trans/utf8_mac.$(OBJEXT): internal/value_type.h
@@ -8492,6 +8543,7 @@ enc/trans/utf_16_32.$(OBJEXT): internal/special_consts.h
enc/trans/utf_16_32.$(OBJEXT): internal/static_assert.h
enc/trans/utf_16_32.$(OBJEXT): internal/stdalign.h
enc/trans/utf_16_32.$(OBJEXT): internal/stdbool.h
+enc/trans/utf_16_32.$(OBJEXT): internal/stdckdint.h
enc/trans/utf_16_32.$(OBJEXT): internal/symbol.h
enc/trans/utf_16_32.$(OBJEXT): internal/value.h
enc/trans/utf_16_32.$(OBJEXT): internal/value_type.h
@@ -8653,6 +8705,7 @@ enc/unicode.$(OBJEXT): internal/special_consts.h
enc/unicode.$(OBJEXT): internal/static_assert.h
enc/unicode.$(OBJEXT): internal/stdalign.h
enc/unicode.$(OBJEXT): internal/stdbool.h
+enc/unicode.$(OBJEXT): internal/stdckdint.h
enc/unicode.$(OBJEXT): internal/symbol.h
enc/unicode.$(OBJEXT): internal/value.h
enc/unicode.$(OBJEXT): internal/value_type.h
@@ -8823,6 +8876,7 @@ enc/us_ascii.$(OBJEXT): internal/special_consts.h
enc/us_ascii.$(OBJEXT): internal/static_assert.h
enc/us_ascii.$(OBJEXT): internal/stdalign.h
enc/us_ascii.$(OBJEXT): internal/stdbool.h
+enc/us_ascii.$(OBJEXT): internal/stdckdint.h
enc/us_ascii.$(OBJEXT): internal/symbol.h
enc/us_ascii.$(OBJEXT): internal/value.h
enc/us_ascii.$(OBJEXT): internal/value_type.h
@@ -8985,6 +9039,7 @@ enc/utf_16be.$(OBJEXT): internal/special_consts.h
enc/utf_16be.$(OBJEXT): internal/static_assert.h
enc/utf_16be.$(OBJEXT): internal/stdalign.h
enc/utf_16be.$(OBJEXT): internal/stdbool.h
+enc/utf_16be.$(OBJEXT): internal/stdckdint.h
enc/utf_16be.$(OBJEXT): internal/symbol.h
enc/utf_16be.$(OBJEXT): internal/value.h
enc/utf_16be.$(OBJEXT): internal/value_type.h
@@ -9146,6 +9201,7 @@ enc/utf_16le.$(OBJEXT): internal/special_consts.h
enc/utf_16le.$(OBJEXT): internal/static_assert.h
enc/utf_16le.$(OBJEXT): internal/stdalign.h
enc/utf_16le.$(OBJEXT): internal/stdbool.h
+enc/utf_16le.$(OBJEXT): internal/stdckdint.h
enc/utf_16le.$(OBJEXT): internal/symbol.h
enc/utf_16le.$(OBJEXT): internal/value.h
enc/utf_16le.$(OBJEXT): internal/value_type.h
@@ -9307,6 +9363,7 @@ enc/utf_32be.$(OBJEXT): internal/special_consts.h
enc/utf_32be.$(OBJEXT): internal/static_assert.h
enc/utf_32be.$(OBJEXT): internal/stdalign.h
enc/utf_32be.$(OBJEXT): internal/stdbool.h
+enc/utf_32be.$(OBJEXT): internal/stdckdint.h
enc/utf_32be.$(OBJEXT): internal/symbol.h
enc/utf_32be.$(OBJEXT): internal/value.h
enc/utf_32be.$(OBJEXT): internal/value_type.h
@@ -9468,6 +9525,7 @@ enc/utf_32le.$(OBJEXT): internal/special_consts.h
enc/utf_32le.$(OBJEXT): internal/static_assert.h
enc/utf_32le.$(OBJEXT): internal/stdalign.h
enc/utf_32le.$(OBJEXT): internal/stdbool.h
+enc/utf_32le.$(OBJEXT): internal/stdckdint.h
enc/utf_32le.$(OBJEXT): internal/symbol.h
enc/utf_32le.$(OBJEXT): internal/value.h
enc/utf_32le.$(OBJEXT): internal/value_type.h
@@ -9638,6 +9696,7 @@ enc/utf_8.$(OBJEXT): internal/special_consts.h
enc/utf_8.$(OBJEXT): internal/static_assert.h
enc/utf_8.$(OBJEXT): internal/stdalign.h
enc/utf_8.$(OBJEXT): internal/stdbool.h
+enc/utf_8.$(OBJEXT): internal/stdckdint.h
enc/utf_8.$(OBJEXT): internal/symbol.h
enc/utf_8.$(OBJEXT): internal/value.h
enc/utf_8.$(OBJEXT): internal/value_type.h
@@ -9800,6 +9859,7 @@ enc/windows_1250.$(OBJEXT): internal/special_consts.h
enc/windows_1250.$(OBJEXT): internal/static_assert.h
enc/windows_1250.$(OBJEXT): internal/stdalign.h
enc/windows_1250.$(OBJEXT): internal/stdbool.h
+enc/windows_1250.$(OBJEXT): internal/stdckdint.h
enc/windows_1250.$(OBJEXT): internal/symbol.h
enc/windows_1250.$(OBJEXT): internal/value.h
enc/windows_1250.$(OBJEXT): internal/value_type.h
@@ -9960,6 +10020,7 @@ enc/windows_1251.$(OBJEXT): internal/special_consts.h
enc/windows_1251.$(OBJEXT): internal/static_assert.h
enc/windows_1251.$(OBJEXT): internal/stdalign.h
enc/windows_1251.$(OBJEXT): internal/stdbool.h
+enc/windows_1251.$(OBJEXT): internal/stdckdint.h
enc/windows_1251.$(OBJEXT): internal/symbol.h
enc/windows_1251.$(OBJEXT): internal/value.h
enc/windows_1251.$(OBJEXT): internal/value_type.h
@@ -10121,6 +10182,7 @@ enc/windows_1252.$(OBJEXT): internal/special_consts.h
enc/windows_1252.$(OBJEXT): internal/static_assert.h
enc/windows_1252.$(OBJEXT): internal/stdalign.h
enc/windows_1252.$(OBJEXT): internal/stdbool.h
+enc/windows_1252.$(OBJEXT): internal/stdckdint.h
enc/windows_1252.$(OBJEXT): internal/symbol.h
enc/windows_1252.$(OBJEXT): internal/value.h
enc/windows_1252.$(OBJEXT): internal/value_type.h
@@ -10281,6 +10343,7 @@ enc/windows_1253.$(OBJEXT): internal/special_consts.h
enc/windows_1253.$(OBJEXT): internal/static_assert.h
enc/windows_1253.$(OBJEXT): internal/stdalign.h
enc/windows_1253.$(OBJEXT): internal/stdbool.h
+enc/windows_1253.$(OBJEXT): internal/stdckdint.h
enc/windows_1253.$(OBJEXT): internal/symbol.h
enc/windows_1253.$(OBJEXT): internal/value.h
enc/windows_1253.$(OBJEXT): internal/value_type.h
@@ -10442,6 +10505,7 @@ enc/windows_1254.$(OBJEXT): internal/special_consts.h
enc/windows_1254.$(OBJEXT): internal/static_assert.h
enc/windows_1254.$(OBJEXT): internal/stdalign.h
enc/windows_1254.$(OBJEXT): internal/stdbool.h
+enc/windows_1254.$(OBJEXT): internal/stdckdint.h
enc/windows_1254.$(OBJEXT): internal/symbol.h
enc/windows_1254.$(OBJEXT): internal/value.h
enc/windows_1254.$(OBJEXT): internal/value_type.h
@@ -10603,6 +10667,7 @@ enc/windows_1257.$(OBJEXT): internal/special_consts.h
enc/windows_1257.$(OBJEXT): internal/static_assert.h
enc/windows_1257.$(OBJEXT): internal/stdalign.h
enc/windows_1257.$(OBJEXT): internal/stdbool.h
+enc/windows_1257.$(OBJEXT): internal/stdckdint.h
enc/windows_1257.$(OBJEXT): internal/symbol.h
enc/windows_1257.$(OBJEXT): internal/value.h
enc/windows_1257.$(OBJEXT): internal/value_type.h
@@ -10766,6 +10831,7 @@ enc/windows_31j.$(OBJEXT): internal/special_consts.h
enc/windows_31j.$(OBJEXT): internal/static_assert.h
enc/windows_31j.$(OBJEXT): internal/stdalign.h
enc/windows_31j.$(OBJEXT): internal/stdbool.h
+enc/windows_31j.$(OBJEXT): internal/stdckdint.h
enc/windows_31j.$(OBJEXT): internal/symbol.h
enc/windows_31j.$(OBJEXT): internal/value.h
enc/windows_31j.$(OBJEXT): internal/value_type.h
diff --git a/enc/encinit.c.erb b/enc/encinit.c.erb
index 120408f8e3..3662ba200d 100644
--- a/enc/encinit.c.erb
+++ b/enc/encinit.c.erb
@@ -1,3 +1,6 @@
+/* Automatically generated from <%= erb.filename %>
+ * Do not edit<%# directly%>.
+ */
/* Copyright 2012 Google Inc. Some Rights Reserved.
* Author: yugui@google.com (Yugui Sonoda)
*/
diff --git a/enc/make_encmake.rb b/enc/make_encmake.rb
index 9761edd6d9..96d1944bcb 100755
--- a/enc/make_encmake.rb
+++ b/enc/make_encmake.rb
@@ -147,10 +147,6 @@ if MODULE_TYPE == :static
Dir.mkdir 'enc'
rescue Errno::EEXIST
end
- File.open("enc/encinit.c", "w") {|f|
- f.puts "/* Automatically generated from enc/encinit.c.erb"
- f.puts " * Do not edit."
- f.puts " */"
- f.puts tmp
- }
+ require 'tool/lib/output'
+ Output.new(path: "enc/encinit.c", ifchange: true).write(tmp)
end
diff --git a/encoding.c b/encoding.c
index df17f63bb1..480cc8bdc6 100644
--- a/encoding.c
+++ b/encoding.c
@@ -1015,13 +1015,22 @@ rb_enc_get(VALUE obj)
return rb_enc_from_index(rb_enc_get_index(obj));
}
+const char *
+rb_enc_inspect_name(rb_encoding *enc)
+{
+ if (enc == global_enc_ascii) {
+ return "BINARY (ASCII-8BIT)";
+ }
+ return enc->name;
+}
+
static rb_encoding*
rb_encoding_check(rb_encoding* enc, VALUE str1, VALUE str2)
{
if (!enc)
rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
- rb_enc_name(rb_enc_get(str1)),
- rb_enc_name(rb_enc_get(str2)));
+ rb_enc_inspect_name(rb_enc_get(str1)),
+ rb_enc_inspect_name(rb_enc_get(str2)));
return enc;
}
@@ -1263,9 +1272,10 @@ enc_inspect(VALUE self)
if (!(enc = DATA_PTR(self)) || rb_enc_from_index(rb_enc_to_index(enc)) != enc) {
rb_raise(rb_eTypeError, "broken Encoding");
}
+
return rb_enc_sprintf(rb_usascii_encoding(),
"#<%"PRIsVALUE":%s%s%s>", rb_obj_class(self),
- rb_enc_name(enc),
+ rb_enc_inspect_name(enc),
(ENC_DUMMY_P(enc) ? " (dummy)" : ""),
rb_enc_autoload_p(enc) ? " (autoload)" : "");
}
diff --git a/enum.c b/enum.c
index 54ccf61c78..dcb374778e 100644
--- a/enum.c
+++ b/enum.c
@@ -870,134 +870,151 @@ ary_inject_op(VALUE ary, VALUE init, VALUE op)
/*
* call-seq:
- * inject(symbol) -> object
- * inject(initial_operand, symbol) -> object
- * inject {|memo, operand| ... } -> object
- * inject(initial_operand) {|memo, operand| ... } -> object
- *
- * Returns an object formed from operands via either:
+ * inject(symbol) -> object
+ * inject(initial_value, symbol) -> object
+ * inject {|memo, value| ... } -> object
+ * inject(initial_value) {|memo, value| ... } -> object
*
- * - A method named by +symbol+.
- * - A block to which each operand is passed.
- *
- * With method-name argument +symbol+,
- * combines operands using the method:
- *
- * # Sum, without initial_operand.
- * (1..4).inject(:+) # => 10
- * # Sum, with initial_operand.
- * (1..4).inject(10, :+) # => 20
+ * Returns the result of applying a reducer to an initial value and
+ * the first element of the Enumerable. It then takes the result and applies the
+ * function to it and the second element of the collection, and so on. The
+ * return value is the result returned by the final call to the function.
*
- * With a block, passes each operand to the block:
- *
- * # Sum of squares, without initial_operand.
- * (1..4).inject {|sum, n| sum + n*n } # => 30
- * # Sum of squares, with initial_operand.
- * (1..4).inject(2) {|sum, n| sum + n*n } # => 32
+ * You can think of
*
- * <b>Operands</b>
+ * [ a, b, c, d ].inject(i) { |r, v| fn(r, v) }
*
- * If argument +initial_operand+ is not given,
- * the operands for +inject+ are simply the elements of +self+.
- * Example calls and their operands:
+ * as being
*
- * - <tt>(1..4).inject(:+)</tt>:: <tt>[1, 2, 3, 4]</tt>.
- * - <tt>(1...4).inject(:+)</tt>:: <tt>[1, 2, 3]</tt>.
- * - <tt>('a'..'d').inject(:+)</tt>:: <tt>['a', 'b', 'c', 'd']</tt>.
- * - <tt>('a'...'d').inject(:+)</tt>:: <tt>['a', 'b', 'c']</tt>.
+ * fn(fn(fn(fn(i, a), b), c), d)
*
- * Examples with first operand (which is <tt>self.first</tt>) of various types:
+ * In a way the +inject+ function _injects_ the function
+ * between the elements of the enumerable.
*
- * # Integer.
- * (1..4).inject(:+) # => 10
- * # Float.
- * [1.0, 2, 3, 4].inject(:+) # => 10.0
- * # Character.
- * ('a'..'d').inject(:+) # => "abcd"
- * # Complex.
- * [Complex(1, 2), 3, 4].inject(:+) # => (8+2i)
+ * +inject+ is aliased as +reduce+. You use it when you want to
+ * _reduce_ a collection to a single value.
*
- * If argument +initial_operand+ is given,
- * the operands for +inject+ are that value plus the elements of +self+.
- * Example calls their operands:
+ * <b>The Calling Sequences</b>
*
- * - <tt>(1..4).inject(10, :+)</tt>:: <tt>[10, 1, 2, 3, 4]</tt>.
- * - <tt>(1...4).inject(10, :+)</tt>:: <tt>[10, 1, 2, 3]</tt>.
- * - <tt>('a'..'d').inject('e', :+)</tt>:: <tt>['e', 'a', 'b', 'c', 'd']</tt>.
- * - <tt>('a'...'d').inject('e', :+)</tt>:: <tt>['e', 'a', 'b', 'c']</tt>.
+ * Let's start with the most verbose:
*
- * Examples with +initial_operand+ of various types:
+ * enum.inject(initial_value) do |result, next_value|
+ * # do something with +result+ and +next_value+
+ * # the value returned by the block becomes the
+ * # value passed in to the next iteration
+ * # as +result+
+ * end
*
- * # Integer.
- * (1..4).inject(2, :+) # => 12
- * # Float.
- * (1..4).inject(2.0, :+) # => 12.0
- * # String.
- * ('a'..'d').inject('foo', :+) # => "fooabcd"
- * # Array.
- * %w[a b c].inject(['x'], :push) # => ["x", "a", "b", "c"]
- * # Complex.
- * (1..4).inject(Complex(2, 2), :+) # => (12+2i)
+ * For example:
*
- * <b>Combination by Given \Method</b>
+ * product = [ 2, 3, 4 ].inject(1) do |result, next_value|
+ * result * next_value
+ * end
+ * product #=> 24
*
- * If the method-name argument +symbol+ is given,
- * the operands are combined by that method:
+ * When this runs, the block is first called with +1+ (the initial value) and
+ * +2+ (the first element of the array). The block returns <tt>1*2</tt>, so on
+ * the next iteration the block is called with +2+ (the previous result) and
+ * +3+. The block returns +6+, and is called one last time with +6+ and +4+.
+ * The result of the block, +24+ becomes the value returned by +inject+. This
+ * code returns the product of the elements in the enumerable.
*
- * - The first and second operands are combined.
- * - That result is combined with the third operand.
- * - That result is combined with the fourth operand.
- * - And so on.
+ * <b>First Shortcut: Default Initial value</b>
*
- * The return value from +inject+ is the result of the last combination.
+ * In the case of the previous example, the initial value, +1+, wasn't really
+ * necessary: the calculation of the product of a list of numbers is self-contained.
*
- * This call to +inject+ computes the sum of the operands:
+ * In these circumstances, you can omit the +initial_value+ parameter. +inject+
+ * will then initially call the block with the first element of the collection
+ * as the +result+ parameter and the second element as the +next_value+.
*
- * (1..4).inject(:+) # => 10
+ * [ 2, 3, 4 ].inject do |result, next_value|
+ * result * next_value
+ * end
*
- * Examples with various methods:
+ * This shortcut is convenient, but can only be used when the block produces a result
+ * which can be passed back to it as a first parameter.
*
- * # Integer addition.
- * (1..4).inject(:+) # => 10
- * # Integer multiplication.
- * (1..4).inject(:*) # => 24
- * # Character range concatenation.
- * ('a'..'d').inject('', :+) # => "abcd"
- * # String array concatenation.
- * %w[foo bar baz].inject('', :+) # => "foobarbaz"
- * # Hash update.
- * h = [{foo: 0, bar: 1}, {baz: 2}, {bat: 3}].inject(:update)
- * h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
- * # Hash conversion to nested arrays.
- * h = {foo: 0, bar: 1}.inject([], :push)
- * h # => [[:foo, 0], [:bar, 1]]
+ * Here's an example where that's not the case: it returns a hash where the keys are words
+ * and the values are the number of occurrences of that word in the enumerable.
*
- * <b>Combination by Given Block</b>
+ * freqs = File.read("README.md")
+ * .scan(/\w{2,}/)
+ * .reduce(Hash.new(0)) do |counts, word|
+ * counts[word] += 1
+ * counts
+ * end
+ * freqs #=> {"Actions"=>4,
+ * "Status"=>5,
+ * "MinGW"=>3,
+ * "https"=>27,
+ * "github"=>10,
+ * "com"=>15, ...
*
- * If a block is given, the operands are passed to the block:
+ * Note that the last line of the block is just the word +counts+. This ensures the
+ * return value of the block is the result that's being calculated.
*
- * - The first call passes the first and second operands.
- * - The second call passes the result of the first call,
- * along with the third operand.
- * - The third call passes the result of the second call,
- * along with the fourth operand.
- * - And so on.
+ * <b>Second Shortcut: a Reducer function</b>
*
- * The return value from +inject+ is the return value from the last block call.
- *
- * This call to +inject+ gives a block
- * that writes the memo and element, and also sums the elements:
+ * A <i>reducer function</i> is a function that takes a partial result and the next value,
+ * returning the next partial result. The block that is given to +inject+ is a reducer.
*
- * (1..4).inject do |memo, element|
- * p "Memo: #{memo}; element: #{element}"
- * memo + element
- * end # => 10
+ * You can also write a reducer as a function and pass the name of that function
+ * (as a symbol) to +inject+. However, for this to work, the function
*
- * Output:
+ * 1. Must be defined on the type of the result value
+ * 2. Must accept a single parameter, the next value in the collection, and
+ * 3. Must return an updated result which will also implement the function.
+ *
+ * Here's an example that adds elements to a string. The two calls invoke the functions
+ * String#concat and String#+ on the result so far, passing it the next value.
+ *
+ * s = [ "cat", " ", "dog" ].inject("", :concat)
+ * s #=> "cat dog"
+ * s = [ "cat", " ", "dog" ].inject("The result is:", :+)
+ * s #=> "The result is: cat dog"
+ *
+ * Here's a more complex example when the result object maintains
+ * state of a different type to the enumerable elements.
+ *
+ * class Turtle
+ *
+ * def initialize
+ * @x = @y = 0
+ * end
+ *
+ * def move(dir)
+ * case dir
+ * when "n" then @y += 1
+ * when "s" then @y -= 1
+ * when "e" then @x += 1
+ * when "w" then @x -= 1
+ * end
+ * self
+ * end
+ * end
+ *
+ * position = "nnneesw".chars.reduce(Turtle.new, :move)
+ * position #=>> #<Turtle:0x00000001052f4698 @y=2, @x=1>
+ *
+ * <b>Third Shortcut: Reducer With no Initial Value</b>
+ *
+ * If your reducer returns a value that it can accept as a parameter, then you
+ * don't have to pass in an initial value. Here <tt>:*</tt> is the name of the
+ * _times_ function:
+ *
+ * product = [ 2, 3, 4 ].inject(:*)
+ * product # => 24
+ *
+ * String concatenation again:
+ *
+ * s = [ "cat", " ", "dog" ].inject(:+)
+ * s #=> "cat dog"
+ *
+ * And an example that converts a hash to an array of two-element subarrays.
*
- * "Memo: 1; element: 2"
- * "Memo: 3; element: 3"
- * "Memo: 6; element: 4"
+ * nested = {foo: 0, bar: 1}.inject([], :push)
+ * nested # => [[:foo, 0], [:bar, 1]]
*
*
*/
diff --git a/error.c b/error.c
index dc032df651..5f8111df57 100644
--- a/error.c
+++ b/error.c
@@ -386,18 +386,28 @@ warn_vsprintf(rb_encoding *enc, const char *file, int line, const char *fmt, va_
return rb_str_cat2(str, "\n");
}
-#define with_warn_vsprintf(file, line, fmt) \
+#define with_warn_vsprintf(enc, file, line, fmt) \
VALUE str; \
va_list args; \
va_start(args, fmt); \
- str = warn_vsprintf(NULL, file, line, fmt, args); \
+ str = warn_vsprintf(enc, file, line, fmt, args); \
va_end(args);
void
rb_compile_warn(const char *file, int line, const char *fmt, ...)
{
if (!NIL_P(ruby_verbose)) {
- with_warn_vsprintf(file, line, fmt) {
+ with_warn_vsprintf(NULL, file, line, fmt) {
+ rb_write_warning_str(str);
+ }
+ }
+}
+
+void
+rb_enc_compile_warn(rb_encoding *enc, const char *file, int line, const char *fmt, ...)
+{
+ if (!NIL_P(ruby_verbose)) {
+ with_warn_vsprintf(enc, file, line, fmt) {
rb_write_warning_str(str);
}
}
@@ -408,7 +418,18 @@ void
rb_compile_warning(const char *file, int line, const char *fmt, ...)
{
if (RTEST(ruby_verbose)) {
- with_warn_vsprintf(file, line, fmt) {
+ with_warn_vsprintf(NULL, file, line, fmt) {
+ rb_write_warning_str(str);
+ }
+ }
+}
+
+/* rb_enc_compile_warning() reports only in verbose mode */
+void
+rb_enc_compile_warning(rb_encoding *enc, const char *file, int line, const char *fmt, ...)
+{
+ if (RTEST(ruby_verbose)) {
+ with_warn_vsprintf(enc, file, line, fmt) {
rb_write_warning_str(str);
}
}
@@ -418,7 +439,7 @@ void
rb_category_compile_warn(rb_warning_category_t category, const char *file, int line, const char *fmt, ...)
{
if (!NIL_P(ruby_verbose)) {
- with_warn_vsprintf(file, line, fmt) {
+ with_warn_vsprintf(NULL, file, line, fmt) {
rb_warn_category(str, rb_warning_category_to_name(category));
}
}
diff --git a/ext/-test-/RUBY_ALIGNOF/depend b/ext/-test-/RUBY_ALIGNOF/depend
index 3011b637e5..25364e55fb 100644
--- a/ext/-test-/RUBY_ALIGNOF/depend
+++ b/ext/-test-/RUBY_ALIGNOF/depend
@@ -147,6 +147,7 @@ c.o: $(hdrdir)/ruby/internal/special_consts.h
c.o: $(hdrdir)/ruby/internal/static_assert.h
c.o: $(hdrdir)/ruby/internal/stdalign.h
c.o: $(hdrdir)/ruby/internal/stdbool.h
+c.o: $(hdrdir)/ruby/internal/stdckdint.h
c.o: $(hdrdir)/ruby/internal/symbol.h
c.o: $(hdrdir)/ruby/internal/value.h
c.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/arith_seq/beg_len_step/depend b/ext/-test-/arith_seq/beg_len_step/depend
index dc807eaa99..702a0037a8 100644
--- a/ext/-test-/arith_seq/beg_len_step/depend
+++ b/ext/-test-/arith_seq/beg_len_step/depend
@@ -146,6 +146,7 @@ beg_len_step.o: $(hdrdir)/ruby/internal/special_consts.h
beg_len_step.o: $(hdrdir)/ruby/internal/static_assert.h
beg_len_step.o: $(hdrdir)/ruby/internal/stdalign.h
beg_len_step.o: $(hdrdir)/ruby/internal/stdbool.h
+beg_len_step.o: $(hdrdir)/ruby/internal/stdckdint.h
beg_len_step.o: $(hdrdir)/ruby/internal/symbol.h
beg_len_step.o: $(hdrdir)/ruby/internal/value.h
beg_len_step.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/arith_seq/extract/depend b/ext/-test-/arith_seq/extract/depend
index 231736b277..fdbd71dfbc 100644
--- a/ext/-test-/arith_seq/extract/depend
+++ b/ext/-test-/arith_seq/extract/depend
@@ -146,6 +146,7 @@ extract.o: $(hdrdir)/ruby/internal/special_consts.h
extract.o: $(hdrdir)/ruby/internal/static_assert.h
extract.o: $(hdrdir)/ruby/internal/stdalign.h
extract.o: $(hdrdir)/ruby/internal/stdbool.h
+extract.o: $(hdrdir)/ruby/internal/stdckdint.h
extract.o: $(hdrdir)/ruby/internal/symbol.h
extract.o: $(hdrdir)/ruby/internal/value.h
extract.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/array/concat/depend b/ext/-test-/array/concat/depend
index d66e7a540f..f2213a42ea 100644
--- a/ext/-test-/array/concat/depend
+++ b/ext/-test-/array/concat/depend
@@ -147,6 +147,7 @@ to_ary_concat.o: $(hdrdir)/ruby/internal/special_consts.h
to_ary_concat.o: $(hdrdir)/ruby/internal/static_assert.h
to_ary_concat.o: $(hdrdir)/ruby/internal/stdalign.h
to_ary_concat.o: $(hdrdir)/ruby/internal/stdbool.h
+to_ary_concat.o: $(hdrdir)/ruby/internal/stdckdint.h
to_ary_concat.o: $(hdrdir)/ruby/internal/symbol.h
to_ary_concat.o: $(hdrdir)/ruby/internal/value.h
to_ary_concat.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/array/resize/depend b/ext/-test-/array/resize/depend
index a9c02b3db2..f88a9d03c1 100644
--- a/ext/-test-/array/resize/depend
+++ b/ext/-test-/array/resize/depend
@@ -146,6 +146,7 @@ resize.o: $(hdrdir)/ruby/internal/special_consts.h
resize.o: $(hdrdir)/ruby/internal/static_assert.h
resize.o: $(hdrdir)/ruby/internal/stdalign.h
resize.o: $(hdrdir)/ruby/internal/stdbool.h
+resize.o: $(hdrdir)/ruby/internal/stdckdint.h
resize.o: $(hdrdir)/ruby/internal/symbol.h
resize.o: $(hdrdir)/ruby/internal/value.h
resize.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/bignum/depend b/ext/-test-/bignum/depend
index d4392bb6a1..078915ab72 100644
--- a/ext/-test-/bignum/depend
+++ b/ext/-test-/bignum/depend
@@ -146,6 +146,7 @@ big2str.o: $(hdrdir)/ruby/internal/special_consts.h
big2str.o: $(hdrdir)/ruby/internal/static_assert.h
big2str.o: $(hdrdir)/ruby/internal/stdalign.h
big2str.o: $(hdrdir)/ruby/internal/stdbool.h
+big2str.o: $(hdrdir)/ruby/internal/stdckdint.h
big2str.o: $(hdrdir)/ruby/internal/symbol.h
big2str.o: $(hdrdir)/ruby/internal/value.h
big2str.o: $(hdrdir)/ruby/internal/value_type.h
@@ -305,6 +306,7 @@ bigzero.o: $(hdrdir)/ruby/internal/special_consts.h
bigzero.o: $(hdrdir)/ruby/internal/static_assert.h
bigzero.o: $(hdrdir)/ruby/internal/stdalign.h
bigzero.o: $(hdrdir)/ruby/internal/stdbool.h
+bigzero.o: $(hdrdir)/ruby/internal/stdckdint.h
bigzero.o: $(hdrdir)/ruby/internal/symbol.h
bigzero.o: $(hdrdir)/ruby/internal/value.h
bigzero.o: $(hdrdir)/ruby/internal/value_type.h
@@ -464,6 +466,7 @@ div.o: $(hdrdir)/ruby/internal/special_consts.h
div.o: $(hdrdir)/ruby/internal/static_assert.h
div.o: $(hdrdir)/ruby/internal/stdalign.h
div.o: $(hdrdir)/ruby/internal/stdbool.h
+div.o: $(hdrdir)/ruby/internal/stdckdint.h
div.o: $(hdrdir)/ruby/internal/symbol.h
div.o: $(hdrdir)/ruby/internal/value.h
div.o: $(hdrdir)/ruby/internal/value_type.h
@@ -624,6 +627,7 @@ 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
@@ -782,6 +786,7 @@ intpack.o: $(hdrdir)/ruby/internal/special_consts.h
intpack.o: $(hdrdir)/ruby/internal/static_assert.h
intpack.o: $(hdrdir)/ruby/internal/stdalign.h
intpack.o: $(hdrdir)/ruby/internal/stdbool.h
+intpack.o: $(hdrdir)/ruby/internal/stdckdint.h
intpack.o: $(hdrdir)/ruby/internal/symbol.h
intpack.o: $(hdrdir)/ruby/internal/value.h
intpack.o: $(hdrdir)/ruby/internal/value_type.h
@@ -941,6 +946,7 @@ mul.o: $(hdrdir)/ruby/internal/special_consts.h
mul.o: $(hdrdir)/ruby/internal/static_assert.h
mul.o: $(hdrdir)/ruby/internal/stdalign.h
mul.o: $(hdrdir)/ruby/internal/stdbool.h
+mul.o: $(hdrdir)/ruby/internal/stdckdint.h
mul.o: $(hdrdir)/ruby/internal/symbol.h
mul.o: $(hdrdir)/ruby/internal/value.h
mul.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1100,6 +1106,7 @@ str2big.o: $(hdrdir)/ruby/internal/special_consts.h
str2big.o: $(hdrdir)/ruby/internal/static_assert.h
str2big.o: $(hdrdir)/ruby/internal/stdalign.h
str2big.o: $(hdrdir)/ruby/internal/stdbool.h
+str2big.o: $(hdrdir)/ruby/internal/stdckdint.h
str2big.o: $(hdrdir)/ruby/internal/symbol.h
str2big.o: $(hdrdir)/ruby/internal/value.h
str2big.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/bug-14834/depend b/ext/-test-/bug-14834/depend
index bf26a571aa..695094fa7a 100644
--- a/ext/-test-/bug-14834/depend
+++ b/ext/-test-/bug-14834/depend
@@ -147,6 +147,7 @@ bug-14384.o: $(hdrdir)/ruby/internal/special_consts.h
bug-14384.o: $(hdrdir)/ruby/internal/static_assert.h
bug-14384.o: $(hdrdir)/ruby/internal/stdalign.h
bug-14384.o: $(hdrdir)/ruby/internal/stdbool.h
+bug-14384.o: $(hdrdir)/ruby/internal/stdckdint.h
bug-14384.o: $(hdrdir)/ruby/internal/symbol.h
bug-14384.o: $(hdrdir)/ruby/internal/value.h
bug-14384.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/bug-3571/depend b/ext/-test-/bug-3571/depend
index 9105093b0d..84517a9c15 100644
--- a/ext/-test-/bug-3571/depend
+++ b/ext/-test-/bug-3571/depend
@@ -147,6 +147,7 @@ bug.o: $(hdrdir)/ruby/internal/special_consts.h
bug.o: $(hdrdir)/ruby/internal/static_assert.h
bug.o: $(hdrdir)/ruby/internal/stdalign.h
bug.o: $(hdrdir)/ruby/internal/stdbool.h
+bug.o: $(hdrdir)/ruby/internal/stdckdint.h
bug.o: $(hdrdir)/ruby/internal/symbol.h
bug.o: $(hdrdir)/ruby/internal/value.h
bug.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/bug-5832/depend b/ext/-test-/bug-5832/depend
index 9105093b0d..84517a9c15 100644
--- a/ext/-test-/bug-5832/depend
+++ b/ext/-test-/bug-5832/depend
@@ -147,6 +147,7 @@ bug.o: $(hdrdir)/ruby/internal/special_consts.h
bug.o: $(hdrdir)/ruby/internal/static_assert.h
bug.o: $(hdrdir)/ruby/internal/stdalign.h
bug.o: $(hdrdir)/ruby/internal/stdbool.h
+bug.o: $(hdrdir)/ruby/internal/stdckdint.h
bug.o: $(hdrdir)/ruby/internal/symbol.h
bug.o: $(hdrdir)/ruby/internal/value.h
bug.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/bug_reporter/depend b/ext/-test-/bug_reporter/depend
index 20882708d1..1c73234247 100644
--- a/ext/-test-/bug_reporter/depend
+++ b/ext/-test-/bug_reporter/depend
@@ -147,6 +147,7 @@ bug_reporter.o: $(hdrdir)/ruby/internal/special_consts.h
bug_reporter.o: $(hdrdir)/ruby/internal/static_assert.h
bug_reporter.o: $(hdrdir)/ruby/internal/stdalign.h
bug_reporter.o: $(hdrdir)/ruby/internal/stdbool.h
+bug_reporter.o: $(hdrdir)/ruby/internal/stdckdint.h
bug_reporter.o: $(hdrdir)/ruby/internal/symbol.h
bug_reporter.o: $(hdrdir)/ruby/internal/value.h
bug_reporter.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/class/depend b/ext/-test-/class/depend
index 0a805f815e..b0595fdc46 100644
--- a/ext/-test-/class/depend
+++ b/ext/-test-/class/depend
@@ -146,6 +146,7 @@ class2name.o: $(hdrdir)/ruby/internal/special_consts.h
class2name.o: $(hdrdir)/ruby/internal/static_assert.h
class2name.o: $(hdrdir)/ruby/internal/stdalign.h
class2name.o: $(hdrdir)/ruby/internal/stdbool.h
+class2name.o: $(hdrdir)/ruby/internal/stdckdint.h
class2name.o: $(hdrdir)/ruby/internal/symbol.h
class2name.o: $(hdrdir)/ruby/internal/value.h
class2name.o: $(hdrdir)/ruby/internal/value_type.h
@@ -305,6 +306,7 @@ 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
diff --git a/ext/-test-/debug/depend b/ext/-test-/debug/depend
index 5feeea6d98..67e32c6aa6 100644
--- a/ext/-test-/debug/depend
+++ b/ext/-test-/debug/depend
@@ -147,6 +147,7 @@ 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
@@ -306,6 +307,7 @@ inspector.o: $(hdrdir)/ruby/internal/special_consts.h
inspector.o: $(hdrdir)/ruby/internal/static_assert.h
inspector.o: $(hdrdir)/ruby/internal/stdalign.h
inspector.o: $(hdrdir)/ruby/internal/stdbool.h
+inspector.o: $(hdrdir)/ruby/internal/stdckdint.h
inspector.o: $(hdrdir)/ruby/internal/symbol.h
inspector.o: $(hdrdir)/ruby/internal/value.h
inspector.o: $(hdrdir)/ruby/internal/value_type.h
@@ -465,6 +467,7 @@ profile_frames.o: $(hdrdir)/ruby/internal/special_consts.h
profile_frames.o: $(hdrdir)/ruby/internal/static_assert.h
profile_frames.o: $(hdrdir)/ruby/internal/stdalign.h
profile_frames.o: $(hdrdir)/ruby/internal/stdbool.h
+profile_frames.o: $(hdrdir)/ruby/internal/stdckdint.h
profile_frames.o: $(hdrdir)/ruby/internal/symbol.h
profile_frames.o: $(hdrdir)/ruby/internal/value.h
profile_frames.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/dln/empty/depend b/ext/-test-/dln/empty/depend
index a460159087..d3e606df57 100644
--- a/ext/-test-/dln/empty/depend
+++ b/ext/-test-/dln/empty/depend
@@ -147,6 +147,7 @@ empty.o: $(hdrdir)/ruby/internal/special_consts.h
empty.o: $(hdrdir)/ruby/internal/static_assert.h
empty.o: $(hdrdir)/ruby/internal/stdalign.h
empty.o: $(hdrdir)/ruby/internal/stdbool.h
+empty.o: $(hdrdir)/ruby/internal/stdckdint.h
empty.o: $(hdrdir)/ruby/internal/symbol.h
empty.o: $(hdrdir)/ruby/internal/value.h
empty.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/enumerator_kw/depend b/ext/-test-/enumerator_kw/depend
index 49ea495421..85daa55b53 100644
--- a/ext/-test-/enumerator_kw/depend
+++ b/ext/-test-/enumerator_kw/depend
@@ -147,6 +147,7 @@ enumerator_kw.o: $(hdrdir)/ruby/internal/special_consts.h
enumerator_kw.o: $(hdrdir)/ruby/internal/static_assert.h
enumerator_kw.o: $(hdrdir)/ruby/internal/stdalign.h
enumerator_kw.o: $(hdrdir)/ruby/internal/stdbool.h
+enumerator_kw.o: $(hdrdir)/ruby/internal/stdckdint.h
enumerator_kw.o: $(hdrdir)/ruby/internal/symbol.h
enumerator_kw.o: $(hdrdir)/ruby/internal/value.h
enumerator_kw.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/exception/depend b/ext/-test-/exception/depend
index 818b4c79df..7a0544b1e1 100644
--- a/ext/-test-/exception/depend
+++ b/ext/-test-/exception/depend
@@ -146,6 +146,7 @@ dataerror.o: $(hdrdir)/ruby/internal/special_consts.h
dataerror.o: $(hdrdir)/ruby/internal/static_assert.h
dataerror.o: $(hdrdir)/ruby/internal/stdalign.h
dataerror.o: $(hdrdir)/ruby/internal/stdbool.h
+dataerror.o: $(hdrdir)/ruby/internal/stdckdint.h
dataerror.o: $(hdrdir)/ruby/internal/symbol.h
dataerror.o: $(hdrdir)/ruby/internal/value.h
dataerror.o: $(hdrdir)/ruby/internal/value_type.h
@@ -315,6 +316,7 @@ enc_raise.o: $(hdrdir)/ruby/internal/special_consts.h
enc_raise.o: $(hdrdir)/ruby/internal/static_assert.h
enc_raise.o: $(hdrdir)/ruby/internal/stdalign.h
enc_raise.o: $(hdrdir)/ruby/internal/stdbool.h
+enc_raise.o: $(hdrdir)/ruby/internal/stdckdint.h
enc_raise.o: $(hdrdir)/ruby/internal/symbol.h
enc_raise.o: $(hdrdir)/ruby/internal/value.h
enc_raise.o: $(hdrdir)/ruby/internal/value_type.h
@@ -476,6 +478,7 @@ ensured.o: $(hdrdir)/ruby/internal/special_consts.h
ensured.o: $(hdrdir)/ruby/internal/static_assert.h
ensured.o: $(hdrdir)/ruby/internal/stdalign.h
ensured.o: $(hdrdir)/ruby/internal/stdbool.h
+ensured.o: $(hdrdir)/ruby/internal/stdckdint.h
ensured.o: $(hdrdir)/ruby/internal/symbol.h
ensured.o: $(hdrdir)/ruby/internal/value.h
ensured.o: $(hdrdir)/ruby/internal/value_type.h
@@ -635,6 +638,7 @@ 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
diff --git a/ext/-test-/fatal/depend b/ext/-test-/fatal/depend
index 45a8c659c4..36b0ad4205 100644
--- a/ext/-test-/fatal/depend
+++ b/ext/-test-/fatal/depend
@@ -1,4 +1,5 @@
# AUTOGENERATED DEPENDENCIES START
+
init.o: $(RUBY_EXTCONF_H)
init.o: $(arch_hdrdir)/ruby/config.h
init.o: $(hdrdir)/ruby.h
@@ -147,6 +148,7 @@ 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
@@ -306,6 +308,7 @@ invalid.o: $(hdrdir)/ruby/internal/special_consts.h
invalid.o: $(hdrdir)/ruby/internal/static_assert.h
invalid.o: $(hdrdir)/ruby/internal/stdalign.h
invalid.o: $(hdrdir)/ruby/internal/stdbool.h
+invalid.o: $(hdrdir)/ruby/internal/stdckdint.h
invalid.o: $(hdrdir)/ruby/internal/symbol.h
invalid.o: $(hdrdir)/ruby/internal/value.h
invalid.o: $(hdrdir)/ruby/internal/value_type.h
@@ -465,6 +468,7 @@ rb_fatal.o: $(hdrdir)/ruby/internal/special_consts.h
rb_fatal.o: $(hdrdir)/ruby/internal/static_assert.h
rb_fatal.o: $(hdrdir)/ruby/internal/stdalign.h
rb_fatal.o: $(hdrdir)/ruby/internal/stdbool.h
+rb_fatal.o: $(hdrdir)/ruby/internal/stdckdint.h
rb_fatal.o: $(hdrdir)/ruby/internal/symbol.h
rb_fatal.o: $(hdrdir)/ruby/internal/value.h
rb_fatal.o: $(hdrdir)/ruby/internal/value_type.h
@@ -476,5 +480,4 @@ rb_fatal.o: $(hdrdir)/ruby/ruby.h
rb_fatal.o: $(hdrdir)/ruby/st.h
rb_fatal.o: $(hdrdir)/ruby/subst.h
rb_fatal.o: rb_fatal.c
-
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/file/depend b/ext/-test-/file/depend
index 2c8a04e433..e985f914b2 100644
--- a/ext/-test-/file/depend
+++ b/ext/-test-/file/depend
@@ -156,6 +156,7 @@ fs.o: $(hdrdir)/ruby/internal/special_consts.h
fs.o: $(hdrdir)/ruby/internal/static_assert.h
fs.o: $(hdrdir)/ruby/internal/stdalign.h
fs.o: $(hdrdir)/ruby/internal/stdbool.h
+fs.o: $(hdrdir)/ruby/internal/stdckdint.h
fs.o: $(hdrdir)/ruby/internal/symbol.h
fs.o: $(hdrdir)/ruby/internal/value.h
fs.o: $(hdrdir)/ruby/internal/value_type.h
@@ -318,6 +319,7 @@ 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
@@ -486,6 +488,7 @@ newline_conv.o: $(hdrdir)/ruby/internal/special_consts.h
newline_conv.o: $(hdrdir)/ruby/internal/static_assert.h
newline_conv.o: $(hdrdir)/ruby/internal/stdalign.h
newline_conv.o: $(hdrdir)/ruby/internal/stdbool.h
+newline_conv.o: $(hdrdir)/ruby/internal/stdckdint.h
newline_conv.o: $(hdrdir)/ruby/internal/symbol.h
newline_conv.o: $(hdrdir)/ruby/internal/value.h
newline_conv.o: $(hdrdir)/ruby/internal/value_type.h
@@ -657,6 +660,7 @@ stat.o: $(hdrdir)/ruby/internal/special_consts.h
stat.o: $(hdrdir)/ruby/internal/static_assert.h
stat.o: $(hdrdir)/ruby/internal/stdalign.h
stat.o: $(hdrdir)/ruby/internal/stdbool.h
+stat.o: $(hdrdir)/ruby/internal/stdckdint.h
stat.o: $(hdrdir)/ruby/internal/symbol.h
stat.o: $(hdrdir)/ruby/internal/value.h
stat.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/float/depend b/ext/-test-/float/depend
index 9580a0416c..3e34818d5f 100644
--- a/ext/-test-/float/depend
+++ b/ext/-test-/float/depend
@@ -150,6 +150,7 @@ 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
@@ -309,6 +310,7 @@ nextafter.o: $(hdrdir)/ruby/internal/special_consts.h
nextafter.o: $(hdrdir)/ruby/internal/static_assert.h
nextafter.o: $(hdrdir)/ruby/internal/stdalign.h
nextafter.o: $(hdrdir)/ruby/internal/stdbool.h
+nextafter.o: $(hdrdir)/ruby/internal/stdckdint.h
nextafter.o: $(hdrdir)/ruby/internal/symbol.h
nextafter.o: $(hdrdir)/ruby/internal/value.h
nextafter.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/funcall/depend b/ext/-test-/funcall/depend
index 6719e4e676..a5a30873ac 100644
--- a/ext/-test-/funcall/depend
+++ b/ext/-test-/funcall/depend
@@ -147,6 +147,7 @@ funcall.o: $(hdrdir)/ruby/internal/special_consts.h
funcall.o: $(hdrdir)/ruby/internal/static_assert.h
funcall.o: $(hdrdir)/ruby/internal/stdalign.h
funcall.o: $(hdrdir)/ruby/internal/stdbool.h
+funcall.o: $(hdrdir)/ruby/internal/stdckdint.h
funcall.o: $(hdrdir)/ruby/internal/symbol.h
funcall.o: $(hdrdir)/ruby/internal/value.h
funcall.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/gvl/call_without_gvl/depend b/ext/-test-/gvl/call_without_gvl/depend
index a4987a65ca..6463d4527d 100644
--- a/ext/-test-/gvl/call_without_gvl/depend
+++ b/ext/-test-/gvl/call_without_gvl/depend
@@ -146,6 +146,7 @@ call_without_gvl.o: $(hdrdir)/ruby/internal/special_consts.h
call_without_gvl.o: $(hdrdir)/ruby/internal/static_assert.h
call_without_gvl.o: $(hdrdir)/ruby/internal/stdalign.h
call_without_gvl.o: $(hdrdir)/ruby/internal/stdbool.h
+call_without_gvl.o: $(hdrdir)/ruby/internal/stdckdint.h
call_without_gvl.o: $(hdrdir)/ruby/internal/symbol.h
call_without_gvl.o: $(hdrdir)/ruby/internal/value.h
call_without_gvl.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/hash/depend b/ext/-test-/hash/depend
index 58d9a6247e..4bc4bfcdd6 100644
--- a/ext/-test-/hash/depend
+++ b/ext/-test-/hash/depend
@@ -147,6 +147,7 @@ delete.o: $(hdrdir)/ruby/internal/special_consts.h
delete.o: $(hdrdir)/ruby/internal/static_assert.h
delete.o: $(hdrdir)/ruby/internal/stdalign.h
delete.o: $(hdrdir)/ruby/internal/stdbool.h
+delete.o: $(hdrdir)/ruby/internal/stdckdint.h
delete.o: $(hdrdir)/ruby/internal/symbol.h
delete.o: $(hdrdir)/ruby/internal/value.h
delete.o: $(hdrdir)/ruby/internal/value_type.h
@@ -306,6 +307,7 @@ 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
diff --git a/ext/-test-/integer/depend b/ext/-test-/integer/depend
index b68a68ce73..d89965e3d9 100644
--- a/ext/-test-/integer/depend
+++ b/ext/-test-/integer/depend
@@ -147,6 +147,7 @@ core_ext.o: $(hdrdir)/ruby/internal/special_consts.h
core_ext.o: $(hdrdir)/ruby/internal/static_assert.h
core_ext.o: $(hdrdir)/ruby/internal/stdalign.h
core_ext.o: $(hdrdir)/ruby/internal/stdbool.h
+core_ext.o: $(hdrdir)/ruby/internal/stdckdint.h
core_ext.o: $(hdrdir)/ruby/internal/symbol.h
core_ext.o: $(hdrdir)/ruby/internal/value.h
core_ext.o: $(hdrdir)/ruby/internal/value_type.h
@@ -314,6 +315,7 @@ 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
@@ -473,6 +475,7 @@ my_integer.o: $(hdrdir)/ruby/internal/special_consts.h
my_integer.o: $(hdrdir)/ruby/internal/static_assert.h
my_integer.o: $(hdrdir)/ruby/internal/stdalign.h
my_integer.o: $(hdrdir)/ruby/internal/stdbool.h
+my_integer.o: $(hdrdir)/ruby/internal/stdckdint.h
my_integer.o: $(hdrdir)/ruby/internal/symbol.h
my_integer.o: $(hdrdir)/ruby/internal/value.h
my_integer.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/iseq_load/depend b/ext/-test-/iseq_load/depend
index 30deb6e039..fd07b3199c 100644
--- a/ext/-test-/iseq_load/depend
+++ b/ext/-test-/iseq_load/depend
@@ -147,6 +147,7 @@ iseq_load.o: $(hdrdir)/ruby/internal/special_consts.h
iseq_load.o: $(hdrdir)/ruby/internal/static_assert.h
iseq_load.o: $(hdrdir)/ruby/internal/stdalign.h
iseq_load.o: $(hdrdir)/ruby/internal/stdbool.h
+iseq_load.o: $(hdrdir)/ruby/internal/stdckdint.h
iseq_load.o: $(hdrdir)/ruby/internal/symbol.h
iseq_load.o: $(hdrdir)/ruby/internal/value.h
iseq_load.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/iter/depend b/ext/-test-/iter/depend
index 077a283532..cff4b1bb43 100644
--- a/ext/-test-/iter/depend
+++ b/ext/-test-/iter/depend
@@ -147,6 +147,7 @@ break.o: $(hdrdir)/ruby/internal/special_consts.h
break.o: $(hdrdir)/ruby/internal/static_assert.h
break.o: $(hdrdir)/ruby/internal/stdalign.h
break.o: $(hdrdir)/ruby/internal/stdbool.h
+break.o: $(hdrdir)/ruby/internal/stdckdint.h
break.o: $(hdrdir)/ruby/internal/symbol.h
break.o: $(hdrdir)/ruby/internal/value.h
break.o: $(hdrdir)/ruby/internal/value_type.h
@@ -306,6 +307,7 @@ 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
@@ -465,6 +467,7 @@ yield.o: $(hdrdir)/ruby/internal/special_consts.h
yield.o: $(hdrdir)/ruby/internal/static_assert.h
yield.o: $(hdrdir)/ruby/internal/stdalign.h
yield.o: $(hdrdir)/ruby/internal/stdbool.h
+yield.o: $(hdrdir)/ruby/internal/stdckdint.h
yield.o: $(hdrdir)/ruby/internal/symbol.h
yield.o: $(hdrdir)/ruby/internal/value.h
yield.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/load/dot.dot/depend b/ext/-test-/load/dot.dot/depend
index be835d3ea5..f9be79e957 100644
--- a/ext/-test-/load/dot.dot/depend
+++ b/ext/-test-/load/dot.dot/depend
@@ -147,6 +147,7 @@ dot.dot.o: $(hdrdir)/ruby/internal/special_consts.h
dot.dot.o: $(hdrdir)/ruby/internal/static_assert.h
dot.dot.o: $(hdrdir)/ruby/internal/stdalign.h
dot.dot.o: $(hdrdir)/ruby/internal/stdbool.h
+dot.dot.o: $(hdrdir)/ruby/internal/stdckdint.h
dot.dot.o: $(hdrdir)/ruby/internal/symbol.h
dot.dot.o: $(hdrdir)/ruby/internal/value.h
dot.dot.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/load/protect/depend b/ext/-test-/load/protect/depend
index 57cf029901..324c17237a 100644
--- a/ext/-test-/load/protect/depend
+++ b/ext/-test-/load/protect/depend
@@ -147,6 +147,7 @@ protect.o: $(hdrdir)/ruby/internal/special_consts.h
protect.o: $(hdrdir)/ruby/internal/static_assert.h
protect.o: $(hdrdir)/ruby/internal/stdalign.h
protect.o: $(hdrdir)/ruby/internal/stdbool.h
+protect.o: $(hdrdir)/ruby/internal/stdckdint.h
protect.o: $(hdrdir)/ruby/internal/symbol.h
protect.o: $(hdrdir)/ruby/internal/value.h
protect.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.h b/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.h
index 7d471bf360..847dcb7dd3 100644
--- a/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.h
+++ b/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.h
@@ -1,4 +1,4 @@
#include <ruby.h>
#include "ruby/internal/dllexport.h"
-RUBY_EXTERN VALUE rst_any_method(VALUE);
+RUBY_FUNC_EXPORTED VALUE rst_any_method(VALUE);
diff --git a/ext/-test-/load/stringify_target/stringify_target.h b/ext/-test-/load/stringify_target/stringify_target.h
index 5081f8cbd6..d95fb65d7c 100644
--- a/ext/-test-/load/stringify_target/stringify_target.h
+++ b/ext/-test-/load/stringify_target/stringify_target.h
@@ -1,4 +1,4 @@
#include <ruby.h>
#include "ruby/internal/dllexport.h"
-RUBY_EXTERN VALUE stt_any_method(VALUE);
+RUBY_FUNC_EXPORTED VALUE stt_any_method(VALUE);
diff --git a/ext/-test-/marshal/compat/depend b/ext/-test-/marshal/compat/depend
index ff675ccabb..8bcd9f8b5e 100644
--- a/ext/-test-/marshal/compat/depend
+++ b/ext/-test-/marshal/compat/depend
@@ -147,6 +147,7 @@ usrcompat.o: $(hdrdir)/ruby/internal/special_consts.h
usrcompat.o: $(hdrdir)/ruby/internal/static_assert.h
usrcompat.o: $(hdrdir)/ruby/internal/stdalign.h
usrcompat.o: $(hdrdir)/ruby/internal/stdbool.h
+usrcompat.o: $(hdrdir)/ruby/internal/stdckdint.h
usrcompat.o: $(hdrdir)/ruby/internal/symbol.h
usrcompat.o: $(hdrdir)/ruby/internal/value.h
usrcompat.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/marshal/internal_ivar/depend b/ext/-test-/marshal/internal_ivar/depend
index 4fe36834d8..f8be031efc 100644
--- a/ext/-test-/marshal/internal_ivar/depend
+++ b/ext/-test-/marshal/internal_ivar/depend
@@ -147,6 +147,7 @@ internal_ivar.o: $(hdrdir)/ruby/internal/special_consts.h
internal_ivar.o: $(hdrdir)/ruby/internal/static_assert.h
internal_ivar.o: $(hdrdir)/ruby/internal/stdalign.h
internal_ivar.o: $(hdrdir)/ruby/internal/stdbool.h
+internal_ivar.o: $(hdrdir)/ruby/internal/stdckdint.h
internal_ivar.o: $(hdrdir)/ruby/internal/symbol.h
internal_ivar.o: $(hdrdir)/ruby/internal/value.h
internal_ivar.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/marshal/usr/depend b/ext/-test-/marshal/usr/depend
index 1d56cc8202..09e8207d3a 100644
--- a/ext/-test-/marshal/usr/depend
+++ b/ext/-test-/marshal/usr/depend
@@ -147,6 +147,7 @@ usrmarshal.o: $(hdrdir)/ruby/internal/special_consts.h
usrmarshal.o: $(hdrdir)/ruby/internal/static_assert.h
usrmarshal.o: $(hdrdir)/ruby/internal/stdalign.h
usrmarshal.o: $(hdrdir)/ruby/internal/stdbool.h
+usrmarshal.o: $(hdrdir)/ruby/internal/stdckdint.h
usrmarshal.o: $(hdrdir)/ruby/internal/symbol.h
usrmarshal.o: $(hdrdir)/ruby/internal/value.h
usrmarshal.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/memory_view/depend b/ext/-test-/memory_view/depend
index c9ef06a15c..0c92fc1236 100644
--- a/ext/-test-/memory_view/depend
+++ b/ext/-test-/memory_view/depend
@@ -147,6 +147,7 @@ memory_view.o: $(hdrdir)/ruby/internal/special_consts.h
memory_view.o: $(hdrdir)/ruby/internal/static_assert.h
memory_view.o: $(hdrdir)/ruby/internal/stdalign.h
memory_view.o: $(hdrdir)/ruby/internal/stdbool.h
+memory_view.o: $(hdrdir)/ruby/internal/stdckdint.h
memory_view.o: $(hdrdir)/ruby/internal/symbol.h
memory_view.o: $(hdrdir)/ruby/internal/value.h
memory_view.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/method/depend b/ext/-test-/method/depend
index dbf513f48f..dce2a815a4 100644
--- a/ext/-test-/method/depend
+++ b/ext/-test-/method/depend
@@ -147,6 +147,7 @@ arity.o: $(hdrdir)/ruby/internal/special_consts.h
arity.o: $(hdrdir)/ruby/internal/static_assert.h
arity.o: $(hdrdir)/ruby/internal/stdalign.h
arity.o: $(hdrdir)/ruby/internal/stdbool.h
+arity.o: $(hdrdir)/ruby/internal/stdckdint.h
arity.o: $(hdrdir)/ruby/internal/symbol.h
arity.o: $(hdrdir)/ruby/internal/value.h
arity.o: $(hdrdir)/ruby/internal/value_type.h
@@ -306,6 +307,7 @@ 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
diff --git a/ext/-test-/notimplement/depend b/ext/-test-/notimplement/depend
index 9105093b0d..84517a9c15 100644
--- a/ext/-test-/notimplement/depend
+++ b/ext/-test-/notimplement/depend
@@ -147,6 +147,7 @@ bug.o: $(hdrdir)/ruby/internal/special_consts.h
bug.o: $(hdrdir)/ruby/internal/static_assert.h
bug.o: $(hdrdir)/ruby/internal/stdalign.h
bug.o: $(hdrdir)/ruby/internal/stdbool.h
+bug.o: $(hdrdir)/ruby/internal/stdckdint.h
bug.o: $(hdrdir)/ruby/internal/symbol.h
bug.o: $(hdrdir)/ruby/internal/value.h
bug.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/num2int/depend b/ext/-test-/num2int/depend
index 4e05d1e8c1..5550033be7 100644
--- a/ext/-test-/num2int/depend
+++ b/ext/-test-/num2int/depend
@@ -147,6 +147,7 @@ num2int.o: $(hdrdir)/ruby/internal/special_consts.h
num2int.o: $(hdrdir)/ruby/internal/static_assert.h
num2int.o: $(hdrdir)/ruby/internal/stdalign.h
num2int.o: $(hdrdir)/ruby/internal/stdbool.h
+num2int.o: $(hdrdir)/ruby/internal/stdckdint.h
num2int.o: $(hdrdir)/ruby/internal/symbol.h
num2int.o: $(hdrdir)/ruby/internal/value.h
num2int.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/path_to_class/depend b/ext/-test-/path_to_class/depend
index 8fe6ee37c2..a1657c9574 100644
--- a/ext/-test-/path_to_class/depend
+++ b/ext/-test-/path_to_class/depend
@@ -147,6 +147,7 @@ path_to_class.o: $(hdrdir)/ruby/internal/special_consts.h
path_to_class.o: $(hdrdir)/ruby/internal/static_assert.h
path_to_class.o: $(hdrdir)/ruby/internal/stdalign.h
path_to_class.o: $(hdrdir)/ruby/internal/stdbool.h
+path_to_class.o: $(hdrdir)/ruby/internal/stdckdint.h
path_to_class.o: $(hdrdir)/ruby/internal/symbol.h
path_to_class.o: $(hdrdir)/ruby/internal/value.h
path_to_class.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/popen_deadlock/depend b/ext/-test-/popen_deadlock/depend
index fb58ca30e9..1904e64e59 100644
--- a/ext/-test-/popen_deadlock/depend
+++ b/ext/-test-/popen_deadlock/depend
@@ -147,6 +147,7 @@ infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/special_consts.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/static_assert.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/stdalign.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/stdbool.h
+infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/stdckdint.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/symbol.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/value.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/postponed_job/depend b/ext/-test-/postponed_job/depend
index e44d9d51b7..72250896b0 100644
--- a/ext/-test-/postponed_job/depend
+++ b/ext/-test-/postponed_job/depend
@@ -148,6 +148,7 @@ postponed_job.o: $(hdrdir)/ruby/internal/special_consts.h
postponed_job.o: $(hdrdir)/ruby/internal/static_assert.h
postponed_job.o: $(hdrdir)/ruby/internal/stdalign.h
postponed_job.o: $(hdrdir)/ruby/internal/stdbool.h
+postponed_job.o: $(hdrdir)/ruby/internal/stdckdint.h
postponed_job.o: $(hdrdir)/ruby/internal/symbol.h
postponed_job.o: $(hdrdir)/ruby/internal/value.h
postponed_job.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/printf/depend b/ext/-test-/printf/depend
index b397041103..0530df78bf 100644
--- a/ext/-test-/printf/depend
+++ b/ext/-test-/printf/depend
@@ -157,6 +157,7 @@ printf.o: $(hdrdir)/ruby/internal/special_consts.h
printf.o: $(hdrdir)/ruby/internal/static_assert.h
printf.o: $(hdrdir)/ruby/internal/stdalign.h
printf.o: $(hdrdir)/ruby/internal/stdbool.h
+printf.o: $(hdrdir)/ruby/internal/stdckdint.h
printf.o: $(hdrdir)/ruby/internal/symbol.h
printf.o: $(hdrdir)/ruby/internal/value.h
printf.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/proc/depend b/ext/-test-/proc/depend
index 7e78aa6f83..45e12bcd09 100644
--- a/ext/-test-/proc/depend
+++ b/ext/-test-/proc/depend
@@ -147,6 +147,7 @@ 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
@@ -306,6 +307,7 @@ receiver.o: $(hdrdir)/ruby/internal/special_consts.h
receiver.o: $(hdrdir)/ruby/internal/static_assert.h
receiver.o: $(hdrdir)/ruby/internal/stdalign.h
receiver.o: $(hdrdir)/ruby/internal/stdbool.h
+receiver.o: $(hdrdir)/ruby/internal/stdckdint.h
receiver.o: $(hdrdir)/ruby/internal/symbol.h
receiver.o: $(hdrdir)/ruby/internal/value.h
receiver.o: $(hdrdir)/ruby/internal/value_type.h
@@ -465,6 +467,7 @@ super.o: $(hdrdir)/ruby/internal/special_consts.h
super.o: $(hdrdir)/ruby/internal/static_assert.h
super.o: $(hdrdir)/ruby/internal/stdalign.h
super.o: $(hdrdir)/ruby/internal/stdbool.h
+super.o: $(hdrdir)/ruby/internal/stdckdint.h
super.o: $(hdrdir)/ruby/internal/symbol.h
super.o: $(hdrdir)/ruby/internal/value.h
super.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/random/depend b/ext/-test-/random/depend
index 3f9a52be44..71f5f6e1e6 100644
--- a/ext/-test-/random/depend
+++ b/ext/-test-/random/depend
@@ -146,6 +146,7 @@ bad_version.o: $(hdrdir)/ruby/internal/special_consts.h
bad_version.o: $(hdrdir)/ruby/internal/static_assert.h
bad_version.o: $(hdrdir)/ruby/internal/stdalign.h
bad_version.o: $(hdrdir)/ruby/internal/stdbool.h
+bad_version.o: $(hdrdir)/ruby/internal/stdckdint.h
bad_version.o: $(hdrdir)/ruby/internal/symbol.h
bad_version.o: $(hdrdir)/ruby/internal/value.h
bad_version.o: $(hdrdir)/ruby/internal/value_type.h
@@ -306,6 +307,7 @@ 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
@@ -464,6 +466,7 @@ loop.o: $(hdrdir)/ruby/internal/special_consts.h
loop.o: $(hdrdir)/ruby/internal/static_assert.h
loop.o: $(hdrdir)/ruby/internal/stdalign.h
loop.o: $(hdrdir)/ruby/internal/stdbool.h
+loop.o: $(hdrdir)/ruby/internal/stdckdint.h
loop.o: $(hdrdir)/ruby/internal/symbol.h
loop.o: $(hdrdir)/ruby/internal/value.h
loop.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/rational/depend b/ext/-test-/rational/depend
index cff2eae38d..363d779302 100644
--- a/ext/-test-/rational/depend
+++ b/ext/-test-/rational/depend
@@ -151,6 +151,7 @@ rat.o: $(hdrdir)/ruby/internal/special_consts.h
rat.o: $(hdrdir)/ruby/internal/static_assert.h
rat.o: $(hdrdir)/ruby/internal/stdalign.h
rat.o: $(hdrdir)/ruby/internal/stdbool.h
+rat.o: $(hdrdir)/ruby/internal/stdckdint.h
rat.o: $(hdrdir)/ruby/internal/symbol.h
rat.o: $(hdrdir)/ruby/internal/value.h
rat.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/rb_call_super_kw/depend b/ext/-test-/rb_call_super_kw/depend
index a42ddc85ac..04a0fac12c 100644
--- a/ext/-test-/rb_call_super_kw/depend
+++ b/ext/-test-/rb_call_super_kw/depend
@@ -147,6 +147,7 @@ rb_call_super_kw.o: $(hdrdir)/ruby/internal/special_consts.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/static_assert.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/stdalign.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/stdbool.h
+rb_call_super_kw.o: $(hdrdir)/ruby/internal/stdckdint.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/symbol.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/value.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/recursion/depend b/ext/-test-/recursion/depend
index 49377250ef..2a65c98b09 100644
--- a/ext/-test-/recursion/depend
+++ b/ext/-test-/recursion/depend
@@ -147,6 +147,7 @@ recursion.o: $(hdrdir)/ruby/internal/special_consts.h
recursion.o: $(hdrdir)/ruby/internal/static_assert.h
recursion.o: $(hdrdir)/ruby/internal/stdalign.h
recursion.o: $(hdrdir)/ruby/internal/stdbool.h
+recursion.o: $(hdrdir)/ruby/internal/stdckdint.h
recursion.o: $(hdrdir)/ruby/internal/symbol.h
recursion.o: $(hdrdir)/ruby/internal/value.h
recursion.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/regexp/depend b/ext/-test-/regexp/depend
index 484f0320dd..0127a66a2e 100644
--- a/ext/-test-/regexp/depend
+++ b/ext/-test-/regexp/depend
@@ -147,6 +147,7 @@ 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
@@ -306,6 +307,7 @@ parse_depth_limit.o: $(hdrdir)/ruby/internal/special_consts.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/static_assert.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/stdalign.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/stdbool.h
+parse_depth_limit.o: $(hdrdir)/ruby/internal/stdckdint.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/symbol.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/value.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/scan_args/depend b/ext/-test-/scan_args/depend
index 3bedc6a7cf..922e5bbd5c 100644
--- a/ext/-test-/scan_args/depend
+++ b/ext/-test-/scan_args/depend
@@ -147,6 +147,7 @@ scan_args.o: $(hdrdir)/ruby/internal/special_consts.h
scan_args.o: $(hdrdir)/ruby/internal/static_assert.h
scan_args.o: $(hdrdir)/ruby/internal/stdalign.h
scan_args.o: $(hdrdir)/ruby/internal/stdbool.h
+scan_args.o: $(hdrdir)/ruby/internal/stdckdint.h
scan_args.o: $(hdrdir)/ruby/internal/symbol.h
scan_args.o: $(hdrdir)/ruby/internal/value.h
scan_args.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/st/foreach/depend b/ext/-test-/st/foreach/depend
index fdfe356805..36273f8df8 100644
--- a/ext/-test-/st/foreach/depend
+++ b/ext/-test-/st/foreach/depend
@@ -147,6 +147,7 @@ foreach.o: $(hdrdir)/ruby/internal/special_consts.h
foreach.o: $(hdrdir)/ruby/internal/static_assert.h
foreach.o: $(hdrdir)/ruby/internal/stdalign.h
foreach.o: $(hdrdir)/ruby/internal/stdbool.h
+foreach.o: $(hdrdir)/ruby/internal/stdckdint.h
foreach.o: $(hdrdir)/ruby/internal/symbol.h
foreach.o: $(hdrdir)/ruby/internal/value.h
foreach.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/st/numhash/depend b/ext/-test-/st/numhash/depend
index ef28c892f3..a0916183b6 100644
--- a/ext/-test-/st/numhash/depend
+++ b/ext/-test-/st/numhash/depend
@@ -147,6 +147,7 @@ numhash.o: $(hdrdir)/ruby/internal/special_consts.h
numhash.o: $(hdrdir)/ruby/internal/static_assert.h
numhash.o: $(hdrdir)/ruby/internal/stdalign.h
numhash.o: $(hdrdir)/ruby/internal/stdbool.h
+numhash.o: $(hdrdir)/ruby/internal/stdckdint.h
numhash.o: $(hdrdir)/ruby/internal/symbol.h
numhash.o: $(hdrdir)/ruby/internal/value.h
numhash.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/st/update/depend b/ext/-test-/st/update/depend
index 2d5ff224a2..96ba194df0 100644
--- a/ext/-test-/st/update/depend
+++ b/ext/-test-/st/update/depend
@@ -147,6 +147,7 @@ update.o: $(hdrdir)/ruby/internal/special_consts.h
update.o: $(hdrdir)/ruby/internal/static_assert.h
update.o: $(hdrdir)/ruby/internal/stdalign.h
update.o: $(hdrdir)/ruby/internal/stdbool.h
+update.o: $(hdrdir)/ruby/internal/stdckdint.h
update.o: $(hdrdir)/ruby/internal/symbol.h
update.o: $(hdrdir)/ruby/internal/value.h
update.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/string/depend b/ext/-test-/string/depend
index f8f58e7d44..044b6109ff 100644
--- a/ext/-test-/string/depend
+++ b/ext/-test-/string/depend
@@ -158,6 +158,7 @@ capacity.o: $(hdrdir)/ruby/internal/special_consts.h
capacity.o: $(hdrdir)/ruby/internal/static_assert.h
capacity.o: $(hdrdir)/ruby/internal/stdalign.h
capacity.o: $(hdrdir)/ruby/internal/stdbool.h
+capacity.o: $(hdrdir)/ruby/internal/stdckdint.h
capacity.o: $(hdrdir)/ruby/internal/symbol.h
capacity.o: $(hdrdir)/ruby/internal/value.h
capacity.o: $(hdrdir)/ruby/internal/value_type.h
@@ -321,6 +322,7 @@ chilled.o: $(hdrdir)/ruby/internal/special_consts.h
chilled.o: $(hdrdir)/ruby/internal/static_assert.h
chilled.o: $(hdrdir)/ruby/internal/stdalign.h
chilled.o: $(hdrdir)/ruby/internal/stdbool.h
+chilled.o: $(hdrdir)/ruby/internal/stdckdint.h
chilled.o: $(hdrdir)/ruby/internal/symbol.h
chilled.o: $(hdrdir)/ruby/internal/value.h
chilled.o: $(hdrdir)/ruby/internal/value_type.h
@@ -489,6 +491,7 @@ coderange.o: $(hdrdir)/ruby/internal/special_consts.h
coderange.o: $(hdrdir)/ruby/internal/static_assert.h
coderange.o: $(hdrdir)/ruby/internal/stdalign.h
coderange.o: $(hdrdir)/ruby/internal/stdbool.h
+coderange.o: $(hdrdir)/ruby/internal/stdckdint.h
coderange.o: $(hdrdir)/ruby/internal/symbol.h
coderange.o: $(hdrdir)/ruby/internal/value.h
coderange.o: $(hdrdir)/ruby/internal/value_type.h
@@ -660,6 +663,7 @@ cstr.o: $(hdrdir)/ruby/internal/special_consts.h
cstr.o: $(hdrdir)/ruby/internal/static_assert.h
cstr.o: $(hdrdir)/ruby/internal/stdalign.h
cstr.o: $(hdrdir)/ruby/internal/stdbool.h
+cstr.o: $(hdrdir)/ruby/internal/stdckdint.h
cstr.o: $(hdrdir)/ruby/internal/symbol.h
cstr.o: $(hdrdir)/ruby/internal/value.h
cstr.o: $(hdrdir)/ruby/internal/value_type.h
@@ -824,6 +828,7 @@ ellipsize.o: $(hdrdir)/ruby/internal/special_consts.h
ellipsize.o: $(hdrdir)/ruby/internal/static_assert.h
ellipsize.o: $(hdrdir)/ruby/internal/stdalign.h
ellipsize.o: $(hdrdir)/ruby/internal/stdbool.h
+ellipsize.o: $(hdrdir)/ruby/internal/stdckdint.h
ellipsize.o: $(hdrdir)/ruby/internal/symbol.h
ellipsize.o: $(hdrdir)/ruby/internal/value.h
ellipsize.o: $(hdrdir)/ruby/internal/value_type.h
@@ -993,6 +998,7 @@ enc_associate.o: $(hdrdir)/ruby/internal/special_consts.h
enc_associate.o: $(hdrdir)/ruby/internal/static_assert.h
enc_associate.o: $(hdrdir)/ruby/internal/stdalign.h
enc_associate.o: $(hdrdir)/ruby/internal/stdbool.h
+enc_associate.o: $(hdrdir)/ruby/internal/stdckdint.h
enc_associate.o: $(hdrdir)/ruby/internal/symbol.h
enc_associate.o: $(hdrdir)/ruby/internal/value.h
enc_associate.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1164,6 +1170,7 @@ enc_dummy.o: $(hdrdir)/ruby/internal/special_consts.h
enc_dummy.o: $(hdrdir)/ruby/internal/static_assert.h
enc_dummy.o: $(hdrdir)/ruby/internal/stdalign.h
enc_dummy.o: $(hdrdir)/ruby/internal/stdbool.h
+enc_dummy.o: $(hdrdir)/ruby/internal/stdckdint.h
enc_dummy.o: $(hdrdir)/ruby/internal/symbol.h
enc_dummy.o: $(hdrdir)/ruby/internal/value.h
enc_dummy.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1334,6 +1341,7 @@ enc_str_buf_cat.o: $(hdrdir)/ruby/internal/special_consts.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/static_assert.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/stdalign.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/stdbool.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/internal/stdckdint.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/symbol.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/value.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1506,6 +1514,7 @@ fstring.o: $(hdrdir)/ruby/internal/special_consts.h
fstring.o: $(hdrdir)/ruby/internal/static_assert.h
fstring.o: $(hdrdir)/ruby/internal/stdalign.h
fstring.o: $(hdrdir)/ruby/internal/stdbool.h
+fstring.o: $(hdrdir)/ruby/internal/stdckdint.h
fstring.o: $(hdrdir)/ruby/internal/symbol.h
fstring.o: $(hdrdir)/ruby/internal/value.h
fstring.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1669,6 +1678,7 @@ 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
@@ -1828,6 +1838,7 @@ modify.o: $(hdrdir)/ruby/internal/special_consts.h
modify.o: $(hdrdir)/ruby/internal/static_assert.h
modify.o: $(hdrdir)/ruby/internal/stdalign.h
modify.o: $(hdrdir)/ruby/internal/stdbool.h
+modify.o: $(hdrdir)/ruby/internal/stdckdint.h
modify.o: $(hdrdir)/ruby/internal/symbol.h
modify.o: $(hdrdir)/ruby/internal/value.h
modify.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1997,6 +2008,7 @@ new.o: $(hdrdir)/ruby/internal/special_consts.h
new.o: $(hdrdir)/ruby/internal/static_assert.h
new.o: $(hdrdir)/ruby/internal/stdalign.h
new.o: $(hdrdir)/ruby/internal/stdbool.h
+new.o: $(hdrdir)/ruby/internal/stdckdint.h
new.o: $(hdrdir)/ruby/internal/symbol.h
new.o: $(hdrdir)/ruby/internal/value.h
new.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2158,6 +2170,7 @@ nofree.o: $(hdrdir)/ruby/internal/special_consts.h
nofree.o: $(hdrdir)/ruby/internal/static_assert.h
nofree.o: $(hdrdir)/ruby/internal/stdalign.h
nofree.o: $(hdrdir)/ruby/internal/stdbool.h
+nofree.o: $(hdrdir)/ruby/internal/stdckdint.h
nofree.o: $(hdrdir)/ruby/internal/symbol.h
nofree.o: $(hdrdir)/ruby/internal/value.h
nofree.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2326,6 +2339,7 @@ normalize.o: $(hdrdir)/ruby/internal/special_consts.h
normalize.o: $(hdrdir)/ruby/internal/static_assert.h
normalize.o: $(hdrdir)/ruby/internal/stdalign.h
normalize.o: $(hdrdir)/ruby/internal/stdbool.h
+normalize.o: $(hdrdir)/ruby/internal/stdckdint.h
normalize.o: $(hdrdir)/ruby/internal/symbol.h
normalize.o: $(hdrdir)/ruby/internal/value.h
normalize.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2498,6 +2512,7 @@ qsort.o: $(hdrdir)/ruby/internal/special_consts.h
qsort.o: $(hdrdir)/ruby/internal/static_assert.h
qsort.o: $(hdrdir)/ruby/internal/stdalign.h
qsort.o: $(hdrdir)/ruby/internal/stdbool.h
+qsort.o: $(hdrdir)/ruby/internal/stdckdint.h
qsort.o: $(hdrdir)/ruby/internal/symbol.h
qsort.o: $(hdrdir)/ruby/internal/value.h
qsort.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2660,6 +2675,7 @@ rb_interned_str.o: $(hdrdir)/ruby/internal/special_consts.h
rb_interned_str.o: $(hdrdir)/ruby/internal/static_assert.h
rb_interned_str.o: $(hdrdir)/ruby/internal/stdalign.h
rb_interned_str.o: $(hdrdir)/ruby/internal/stdbool.h
+rb_interned_str.o: $(hdrdir)/ruby/internal/stdckdint.h
rb_interned_str.o: $(hdrdir)/ruby/internal/symbol.h
rb_interned_str.o: $(hdrdir)/ruby/internal/value.h
rb_interned_str.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2819,6 +2835,7 @@ rb_str_dup.o: $(hdrdir)/ruby/internal/special_consts.h
rb_str_dup.o: $(hdrdir)/ruby/internal/static_assert.h
rb_str_dup.o: $(hdrdir)/ruby/internal/stdalign.h
rb_str_dup.o: $(hdrdir)/ruby/internal/stdbool.h
+rb_str_dup.o: $(hdrdir)/ruby/internal/stdckdint.h
rb_str_dup.o: $(hdrdir)/ruby/internal/symbol.h
rb_str_dup.o: $(hdrdir)/ruby/internal/value.h
rb_str_dup.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2978,6 +2995,7 @@ set_len.o: $(hdrdir)/ruby/internal/special_consts.h
set_len.o: $(hdrdir)/ruby/internal/static_assert.h
set_len.o: $(hdrdir)/ruby/internal/stdalign.h
set_len.o: $(hdrdir)/ruby/internal/stdbool.h
+set_len.o: $(hdrdir)/ruby/internal/stdckdint.h
set_len.o: $(hdrdir)/ruby/internal/symbol.h
set_len.o: $(hdrdir)/ruby/internal/value.h
set_len.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/struct/depend b/ext/-test-/struct/depend
index 5db943e286..951dddd5dd 100644
--- a/ext/-test-/struct/depend
+++ b/ext/-test-/struct/depend
@@ -147,6 +147,7 @@ data.o: $(hdrdir)/ruby/internal/special_consts.h
data.o: $(hdrdir)/ruby/internal/static_assert.h
data.o: $(hdrdir)/ruby/internal/stdalign.h
data.o: $(hdrdir)/ruby/internal/stdbool.h
+data.o: $(hdrdir)/ruby/internal/stdckdint.h
data.o: $(hdrdir)/ruby/internal/symbol.h
data.o: $(hdrdir)/ruby/internal/value.h
data.o: $(hdrdir)/ruby/internal/value_type.h
@@ -306,6 +307,7 @@ duplicate.o: $(hdrdir)/ruby/internal/special_consts.h
duplicate.o: $(hdrdir)/ruby/internal/static_assert.h
duplicate.o: $(hdrdir)/ruby/internal/stdalign.h
duplicate.o: $(hdrdir)/ruby/internal/stdbool.h
+duplicate.o: $(hdrdir)/ruby/internal/stdckdint.h
duplicate.o: $(hdrdir)/ruby/internal/symbol.h
duplicate.o: $(hdrdir)/ruby/internal/value.h
duplicate.o: $(hdrdir)/ruby/internal/value_type.h
@@ -465,6 +467,7 @@ 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
@@ -624,6 +627,7 @@ len.o: $(hdrdir)/ruby/internal/special_consts.h
len.o: $(hdrdir)/ruby/internal/static_assert.h
len.o: $(hdrdir)/ruby/internal/stdalign.h
len.o: $(hdrdir)/ruby/internal/stdbool.h
+len.o: $(hdrdir)/ruby/internal/stdckdint.h
len.o: $(hdrdir)/ruby/internal/symbol.h
len.o: $(hdrdir)/ruby/internal/value.h
len.o: $(hdrdir)/ruby/internal/value_type.h
@@ -783,6 +787,7 @@ member.o: $(hdrdir)/ruby/internal/special_consts.h
member.o: $(hdrdir)/ruby/internal/static_assert.h
member.o: $(hdrdir)/ruby/internal/stdalign.h
member.o: $(hdrdir)/ruby/internal/stdbool.h
+member.o: $(hdrdir)/ruby/internal/stdckdint.h
member.o: $(hdrdir)/ruby/internal/symbol.h
member.o: $(hdrdir)/ruby/internal/value.h
member.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/symbol/depend b/ext/-test-/symbol/depend
index dd1b5c305f..7c76596fdf 100644
--- a/ext/-test-/symbol/depend
+++ b/ext/-test-/symbol/depend
@@ -147,6 +147,7 @@ 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
@@ -306,6 +307,7 @@ type.o: $(hdrdir)/ruby/internal/special_consts.h
type.o: $(hdrdir)/ruby/internal/static_assert.h
type.o: $(hdrdir)/ruby/internal/stdalign.h
type.o: $(hdrdir)/ruby/internal/stdbool.h
+type.o: $(hdrdir)/ruby/internal/stdckdint.h
type.o: $(hdrdir)/ruby/internal/symbol.h
type.o: $(hdrdir)/ruby/internal/value.h
type.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/thread/instrumentation/depend b/ext/-test-/thread/instrumentation/depend
index b03f51870f..a37e4d5675 100644
--- a/ext/-test-/thread/instrumentation/depend
+++ b/ext/-test-/thread/instrumentation/depend
@@ -147,6 +147,7 @@ instrumentation.o: $(hdrdir)/ruby/internal/special_consts.h
instrumentation.o: $(hdrdir)/ruby/internal/static_assert.h
instrumentation.o: $(hdrdir)/ruby/internal/stdalign.h
instrumentation.o: $(hdrdir)/ruby/internal/stdbool.h
+instrumentation.o: $(hdrdir)/ruby/internal/stdckdint.h
instrumentation.o: $(hdrdir)/ruby/internal/symbol.h
instrumentation.o: $(hdrdir)/ruby/internal/value.h
instrumentation.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/thread_fd/depend b/ext/-test-/thread_fd/depend
index d4cc772526..0fda9f6dbf 100644
--- a/ext/-test-/thread_fd/depend
+++ b/ext/-test-/thread_fd/depend
@@ -146,6 +146,7 @@ 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
diff --git a/ext/-test-/time/depend b/ext/-test-/time/depend
index c015588b09..5ed791bcc5 100644
--- a/ext/-test-/time/depend
+++ b/ext/-test-/time/depend
@@ -147,6 +147,7 @@ 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
@@ -307,6 +308,7 @@ leap_second.o: $(hdrdir)/ruby/internal/special_consts.h
leap_second.o: $(hdrdir)/ruby/internal/static_assert.h
leap_second.o: $(hdrdir)/ruby/internal/stdalign.h
leap_second.o: $(hdrdir)/ruby/internal/stdbool.h
+leap_second.o: $(hdrdir)/ruby/internal/stdckdint.h
leap_second.o: $(hdrdir)/ruby/internal/symbol.h
leap_second.o: $(hdrdir)/ruby/internal/value.h
leap_second.o: $(hdrdir)/ruby/internal/value_type.h
@@ -470,6 +472,7 @@ new.o: $(hdrdir)/ruby/internal/special_consts.h
new.o: $(hdrdir)/ruby/internal/static_assert.h
new.o: $(hdrdir)/ruby/internal/stdalign.h
new.o: $(hdrdir)/ruby/internal/stdbool.h
+new.o: $(hdrdir)/ruby/internal/stdckdint.h
new.o: $(hdrdir)/ruby/internal/symbol.h
new.o: $(hdrdir)/ruby/internal/value.h
new.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/tracepoint/depend b/ext/-test-/tracepoint/depend
index 396004926e..133663b3bd 100644
--- a/ext/-test-/tracepoint/depend
+++ b/ext/-test-/tracepoint/depend
@@ -147,6 +147,7 @@ gc_hook.o: $(hdrdir)/ruby/internal/special_consts.h
gc_hook.o: $(hdrdir)/ruby/internal/static_assert.h
gc_hook.o: $(hdrdir)/ruby/internal/stdalign.h
gc_hook.o: $(hdrdir)/ruby/internal/stdbool.h
+gc_hook.o: $(hdrdir)/ruby/internal/stdckdint.h
gc_hook.o: $(hdrdir)/ruby/internal/symbol.h
gc_hook.o: $(hdrdir)/ruby/internal/value.h
gc_hook.o: $(hdrdir)/ruby/internal/value_type.h
@@ -306,6 +307,7 @@ tracepoint.o: $(hdrdir)/ruby/internal/special_consts.h
tracepoint.o: $(hdrdir)/ruby/internal/static_assert.h
tracepoint.o: $(hdrdir)/ruby/internal/stdalign.h
tracepoint.o: $(hdrdir)/ruby/internal/stdbool.h
+tracepoint.o: $(hdrdir)/ruby/internal/stdckdint.h
tracepoint.o: $(hdrdir)/ruby/internal/symbol.h
tracepoint.o: $(hdrdir)/ruby/internal/value.h
tracepoint.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/typeddata/depend b/ext/-test-/typeddata/depend
index cbeafa8000..6c0847c82d 100644
--- a/ext/-test-/typeddata/depend
+++ b/ext/-test-/typeddata/depend
@@ -147,6 +147,7 @@ typeddata.o: $(hdrdir)/ruby/internal/special_consts.h
typeddata.o: $(hdrdir)/ruby/internal/static_assert.h
typeddata.o: $(hdrdir)/ruby/internal/stdalign.h
typeddata.o: $(hdrdir)/ruby/internal/stdbool.h
+typeddata.o: $(hdrdir)/ruby/internal/stdckdint.h
typeddata.o: $(hdrdir)/ruby/internal/symbol.h
typeddata.o: $(hdrdir)/ruby/internal/value.h
typeddata.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/vm/depend b/ext/-test-/vm/depend
index f0b3f3b1f4..422b40a32d 100644
--- a/ext/-test-/vm/depend
+++ b/ext/-test-/vm/depend
@@ -146,6 +146,7 @@ at_exit.o: $(hdrdir)/ruby/internal/special_consts.h
at_exit.o: $(hdrdir)/ruby/internal/static_assert.h
at_exit.o: $(hdrdir)/ruby/internal/stdalign.h
at_exit.o: $(hdrdir)/ruby/internal/stdbool.h
+at_exit.o: $(hdrdir)/ruby/internal/stdckdint.h
at_exit.o: $(hdrdir)/ruby/internal/symbol.h
at_exit.o: $(hdrdir)/ruby/internal/value.h
at_exit.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/wait/depend b/ext/-test-/wait/depend
index 2e4887559c..7997a16709 100644
--- a/ext/-test-/wait/depend
+++ b/ext/-test-/wait/depend
@@ -156,6 +156,7 @@ wait.o: $(hdrdir)/ruby/internal/special_consts.h
wait.o: $(hdrdir)/ruby/internal/static_assert.h
wait.o: $(hdrdir)/ruby/internal/stdalign.h
wait.o: $(hdrdir)/ruby/internal/stdbool.h
+wait.o: $(hdrdir)/ruby/internal/stdckdint.h
wait.o: $(hdrdir)/ruby/internal/symbol.h
wait.o: $(hdrdir)/ruby/internal/value.h
wait.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/cgi/escape/depend b/ext/cgi/escape/depend
index 37304a24f4..746b47246a 100644
--- a/ext/cgi/escape/depend
+++ b/ext/cgi/escape/depend
@@ -157,6 +157,7 @@ escape.o: $(hdrdir)/ruby/internal/special_consts.h
escape.o: $(hdrdir)/ruby/internal/static_assert.h
escape.o: $(hdrdir)/ruby/internal/stdalign.h
escape.o: $(hdrdir)/ruby/internal/stdbool.h
+escape.o: $(hdrdir)/ruby/internal/stdckdint.h
escape.o: $(hdrdir)/ruby/internal/symbol.h
escape.o: $(hdrdir)/ruby/internal/value.h
escape.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/continuation/depend b/ext/continuation/depend
index f0333d7fe6..b40e52e29b 100644
--- a/ext/continuation/depend
+++ b/ext/continuation/depend
@@ -146,6 +146,7 @@ continuation.o: $(hdrdir)/ruby/internal/special_consts.h
continuation.o: $(hdrdir)/ruby/internal/static_assert.h
continuation.o: $(hdrdir)/ruby/internal/stdalign.h
continuation.o: $(hdrdir)/ruby/internal/stdbool.h
+continuation.o: $(hdrdir)/ruby/internal/stdckdint.h
continuation.o: $(hdrdir)/ruby/internal/symbol.h
continuation.o: $(hdrdir)/ruby/internal/value.h
continuation.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/coverage/depend b/ext/coverage/depend
index 0a6c61d5c6..1be81c5e9a 100644
--- a/ext/coverage/depend
+++ b/ext/coverage/depend
@@ -159,6 +159,7 @@ coverage.o: $(hdrdir)/ruby/internal/special_consts.h
coverage.o: $(hdrdir)/ruby/internal/static_assert.h
coverage.o: $(hdrdir)/ruby/internal/stdalign.h
coverage.o: $(hdrdir)/ruby/internal/stdbool.h
+coverage.o: $(hdrdir)/ruby/internal/stdckdint.h
coverage.o: $(hdrdir)/ruby/internal/symbol.h
coverage.o: $(hdrdir)/ruby/internal/value.h
coverage.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/date/depend b/ext/date/depend
index 82f85f7bf3..d07f10a593 100644
--- a/ext/date/depend
+++ b/ext/date/depend
@@ -157,6 +157,7 @@ date_core.o: $(hdrdir)/ruby/internal/special_consts.h
date_core.o: $(hdrdir)/ruby/internal/static_assert.h
date_core.o: $(hdrdir)/ruby/internal/stdalign.h
date_core.o: $(hdrdir)/ruby/internal/stdbool.h
+date_core.o: $(hdrdir)/ruby/internal/stdckdint.h
date_core.o: $(hdrdir)/ruby/internal/symbol.h
date_core.o: $(hdrdir)/ruby/internal/value.h
date_core.o: $(hdrdir)/ruby/internal/value_type.h
@@ -331,6 +332,7 @@ date_parse.o: $(hdrdir)/ruby/internal/special_consts.h
date_parse.o: $(hdrdir)/ruby/internal/static_assert.h
date_parse.o: $(hdrdir)/ruby/internal/stdalign.h
date_parse.o: $(hdrdir)/ruby/internal/stdbool.h
+date_parse.o: $(hdrdir)/ruby/internal/stdckdint.h
date_parse.o: $(hdrdir)/ruby/internal/symbol.h
date_parse.o: $(hdrdir)/ruby/internal/value.h
date_parse.o: $(hdrdir)/ruby/internal/value_type.h
@@ -495,6 +497,7 @@ date_strftime.o: $(hdrdir)/ruby/internal/special_consts.h
date_strftime.o: $(hdrdir)/ruby/internal/static_assert.h
date_strftime.o: $(hdrdir)/ruby/internal/stdalign.h
date_strftime.o: $(hdrdir)/ruby/internal/stdbool.h
+date_strftime.o: $(hdrdir)/ruby/internal/stdckdint.h
date_strftime.o: $(hdrdir)/ruby/internal/symbol.h
date_strftime.o: $(hdrdir)/ruby/internal/value.h
date_strftime.o: $(hdrdir)/ruby/internal/value_type.h
@@ -666,6 +669,7 @@ date_strptime.o: $(hdrdir)/ruby/internal/special_consts.h
date_strptime.o: $(hdrdir)/ruby/internal/static_assert.h
date_strptime.o: $(hdrdir)/ruby/internal/stdalign.h
date_strptime.o: $(hdrdir)/ruby/internal/stdbool.h
+date_strptime.o: $(hdrdir)/ruby/internal/stdckdint.h
date_strptime.o: $(hdrdir)/ruby/internal/symbol.h
date_strptime.o: $(hdrdir)/ruby/internal/value.h
date_strptime.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/digest/bubblebabble/depend b/ext/digest/bubblebabble/depend
index 6f0003a66d..0da9c223ee 100644
--- a/ext/digest/bubblebabble/depend
+++ b/ext/digest/bubblebabble/depend
@@ -147,6 +147,7 @@ bubblebabble.o: $(hdrdir)/ruby/internal/special_consts.h
bubblebabble.o: $(hdrdir)/ruby/internal/static_assert.h
bubblebabble.o: $(hdrdir)/ruby/internal/stdalign.h
bubblebabble.o: $(hdrdir)/ruby/internal/stdbool.h
+bubblebabble.o: $(hdrdir)/ruby/internal/stdckdint.h
bubblebabble.o: $(hdrdir)/ruby/internal/symbol.h
bubblebabble.o: $(hdrdir)/ruby/internal/value.h
bubblebabble.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/digest/depend b/ext/digest/depend
index 6df940a679..cb9e8d4813 100644
--- a/ext/digest/depend
+++ b/ext/digest/depend
@@ -147,6 +147,7 @@ digest.o: $(hdrdir)/ruby/internal/special_consts.h
digest.o: $(hdrdir)/ruby/internal/static_assert.h
digest.o: $(hdrdir)/ruby/internal/stdalign.h
digest.o: $(hdrdir)/ruby/internal/stdbool.h
+digest.o: $(hdrdir)/ruby/internal/stdckdint.h
digest.o: $(hdrdir)/ruby/internal/symbol.h
digest.o: $(hdrdir)/ruby/internal/value.h
digest.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/digest/md5/depend b/ext/digest/md5/depend
index da1b345999..e71915e5b4 100644
--- a/ext/digest/md5/depend
+++ b/ext/digest/md5/depend
@@ -150,6 +150,7 @@ md5.o: $(hdrdir)/ruby/internal/special_consts.h
md5.o: $(hdrdir)/ruby/internal/static_assert.h
md5.o: $(hdrdir)/ruby/internal/stdalign.h
md5.o: $(hdrdir)/ruby/internal/stdbool.h
+md5.o: $(hdrdir)/ruby/internal/stdckdint.h
md5.o: $(hdrdir)/ruby/internal/symbol.h
md5.o: $(hdrdir)/ruby/internal/value.h
md5.o: $(hdrdir)/ruby/internal/value_type.h
@@ -311,6 +312,7 @@ md5init.o: $(hdrdir)/ruby/internal/special_consts.h
md5init.o: $(hdrdir)/ruby/internal/static_assert.h
md5init.o: $(hdrdir)/ruby/internal/stdalign.h
md5init.o: $(hdrdir)/ruby/internal/stdbool.h
+md5init.o: $(hdrdir)/ruby/internal/stdckdint.h
md5init.o: $(hdrdir)/ruby/internal/symbol.h
md5init.o: $(hdrdir)/ruby/internal/value.h
md5init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/digest/rmd160/depend b/ext/digest/rmd160/depend
index abfa08b023..09558ad92b 100644
--- a/ext/digest/rmd160/depend
+++ b/ext/digest/rmd160/depend
@@ -150,6 +150,7 @@ rmd160.o: $(hdrdir)/ruby/internal/special_consts.h
rmd160.o: $(hdrdir)/ruby/internal/static_assert.h
rmd160.o: $(hdrdir)/ruby/internal/stdalign.h
rmd160.o: $(hdrdir)/ruby/internal/stdbool.h
+rmd160.o: $(hdrdir)/ruby/internal/stdckdint.h
rmd160.o: $(hdrdir)/ruby/internal/symbol.h
rmd160.o: $(hdrdir)/ruby/internal/value.h
rmd160.o: $(hdrdir)/ruby/internal/value_type.h
@@ -311,6 +312,7 @@ rmd160init.o: $(hdrdir)/ruby/internal/special_consts.h
rmd160init.o: $(hdrdir)/ruby/internal/static_assert.h
rmd160init.o: $(hdrdir)/ruby/internal/stdalign.h
rmd160init.o: $(hdrdir)/ruby/internal/stdbool.h
+rmd160init.o: $(hdrdir)/ruby/internal/stdckdint.h
rmd160init.o: $(hdrdir)/ruby/internal/symbol.h
rmd160init.o: $(hdrdir)/ruby/internal/value.h
rmd160init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/digest/sha1/depend b/ext/digest/sha1/depend
index d17338e92b..827b8a0852 100644
--- a/ext/digest/sha1/depend
+++ b/ext/digest/sha1/depend
@@ -150,6 +150,7 @@ sha1.o: $(hdrdir)/ruby/internal/special_consts.h
sha1.o: $(hdrdir)/ruby/internal/static_assert.h
sha1.o: $(hdrdir)/ruby/internal/stdalign.h
sha1.o: $(hdrdir)/ruby/internal/stdbool.h
+sha1.o: $(hdrdir)/ruby/internal/stdckdint.h
sha1.o: $(hdrdir)/ruby/internal/symbol.h
sha1.o: $(hdrdir)/ruby/internal/value.h
sha1.o: $(hdrdir)/ruby/internal/value_type.h
@@ -311,6 +312,7 @@ sha1init.o: $(hdrdir)/ruby/internal/special_consts.h
sha1init.o: $(hdrdir)/ruby/internal/static_assert.h
sha1init.o: $(hdrdir)/ruby/internal/stdalign.h
sha1init.o: $(hdrdir)/ruby/internal/stdbool.h
+sha1init.o: $(hdrdir)/ruby/internal/stdckdint.h
sha1init.o: $(hdrdir)/ruby/internal/symbol.h
sha1init.o: $(hdrdir)/ruby/internal/value.h
sha1init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/digest/sha2/depend b/ext/digest/sha2/depend
index 7b88b6411f..af1600d346 100644
--- a/ext/digest/sha2/depend
+++ b/ext/digest/sha2/depend
@@ -150,6 +150,7 @@ sha2.o: $(hdrdir)/ruby/internal/special_consts.h
sha2.o: $(hdrdir)/ruby/internal/static_assert.h
sha2.o: $(hdrdir)/ruby/internal/stdalign.h
sha2.o: $(hdrdir)/ruby/internal/stdbool.h
+sha2.o: $(hdrdir)/ruby/internal/stdckdint.h
sha2.o: $(hdrdir)/ruby/internal/symbol.h
sha2.o: $(hdrdir)/ruby/internal/value.h
sha2.o: $(hdrdir)/ruby/internal/value_type.h
@@ -311,6 +312,7 @@ sha2init.o: $(hdrdir)/ruby/internal/special_consts.h
sha2init.o: $(hdrdir)/ruby/internal/static_assert.h
sha2init.o: $(hdrdir)/ruby/internal/stdalign.h
sha2init.o: $(hdrdir)/ruby/internal/stdbool.h
+sha2init.o: $(hdrdir)/ruby/internal/stdckdint.h
sha2init.o: $(hdrdir)/ruby/internal/symbol.h
sha2init.o: $(hdrdir)/ruby/internal/value.h
sha2init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/etc/depend b/ext/etc/depend
index 00787b6aaf..675699b129 100644
--- a/ext/etc/depend
+++ b/ext/etc/depend
@@ -162,6 +162,7 @@ etc.o: $(hdrdir)/ruby/internal/special_consts.h
etc.o: $(hdrdir)/ruby/internal/static_assert.h
etc.o: $(hdrdir)/ruby/internal/stdalign.h
etc.o: $(hdrdir)/ruby/internal/stdbool.h
+etc.o: $(hdrdir)/ruby/internal/stdckdint.h
etc.o: $(hdrdir)/ruby/internal/symbol.h
etc.o: $(hdrdir)/ruby/internal/value.h
etc.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/extmk.rb b/ext/extmk.rb
index 6c7c7aeab7..2f76e174d5 100755
--- a/ext/extmk.rb
+++ b/ext/extmk.rb
@@ -773,7 +773,6 @@ begin
end
submakeopts << 'EXTLDFLAGS="$(EXTLDFLAGS)"'
submakeopts << 'EXTINITS="$(EXTINITS)"'
- submakeopts << 'UPDATE_LIBRARIES="$(UPDATE_LIBRARIES)"'
submakeopts << 'SHOWFLAGS='
mf.macro "SUBMAKEOPTS", submakeopts
mf.macro "NOTE_MESG", %w[$(RUBY) $(top_srcdir)/tool/lib/colorize.rb skip]
diff --git a/ext/fcntl/depend b/ext/fcntl/depend
index 9ce9fa30ef..5ed652563b 100644
--- a/ext/fcntl/depend
+++ b/ext/fcntl/depend
@@ -147,6 +147,7 @@ fcntl.o: $(hdrdir)/ruby/internal/special_consts.h
fcntl.o: $(hdrdir)/ruby/internal/static_assert.h
fcntl.o: $(hdrdir)/ruby/internal/stdalign.h
fcntl.o: $(hdrdir)/ruby/internal/stdbool.h
+fcntl.o: $(hdrdir)/ruby/internal/stdckdint.h
fcntl.o: $(hdrdir)/ruby/internal/symbol.h
fcntl.o: $(hdrdir)/ruby/internal/value.h
fcntl.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/fiddle/depend b/ext/fiddle/depend
index 561785275e..43b11ca780 100644
--- a/ext/fiddle/depend
+++ b/ext/fiddle/depend
@@ -200,6 +200,7 @@ closure.o: $(hdrdir)/ruby/internal/special_consts.h
closure.o: $(hdrdir)/ruby/internal/static_assert.h
closure.o: $(hdrdir)/ruby/internal/stdalign.h
closure.o: $(hdrdir)/ruby/internal/stdbool.h
+closure.o: $(hdrdir)/ruby/internal/stdckdint.h
closure.o: $(hdrdir)/ruby/internal/symbol.h
closure.o: $(hdrdir)/ruby/internal/value.h
closure.o: $(hdrdir)/ruby/internal/value_type.h
@@ -364,6 +365,7 @@ conversions.o: $(hdrdir)/ruby/internal/special_consts.h
conversions.o: $(hdrdir)/ruby/internal/static_assert.h
conversions.o: $(hdrdir)/ruby/internal/stdalign.h
conversions.o: $(hdrdir)/ruby/internal/stdbool.h
+conversions.o: $(hdrdir)/ruby/internal/stdckdint.h
conversions.o: $(hdrdir)/ruby/internal/symbol.h
conversions.o: $(hdrdir)/ruby/internal/value.h
conversions.o: $(hdrdir)/ruby/internal/value_type.h
@@ -527,6 +529,7 @@ fiddle.o: $(hdrdir)/ruby/internal/special_consts.h
fiddle.o: $(hdrdir)/ruby/internal/static_assert.h
fiddle.o: $(hdrdir)/ruby/internal/stdalign.h
fiddle.o: $(hdrdir)/ruby/internal/stdbool.h
+fiddle.o: $(hdrdir)/ruby/internal/stdckdint.h
fiddle.o: $(hdrdir)/ruby/internal/symbol.h
fiddle.o: $(hdrdir)/ruby/internal/value.h
fiddle.o: $(hdrdir)/ruby/internal/value_type.h
@@ -690,6 +693,7 @@ function.o: $(hdrdir)/ruby/internal/special_consts.h
function.o: $(hdrdir)/ruby/internal/static_assert.h
function.o: $(hdrdir)/ruby/internal/stdalign.h
function.o: $(hdrdir)/ruby/internal/stdbool.h
+function.o: $(hdrdir)/ruby/internal/stdckdint.h
function.o: $(hdrdir)/ruby/internal/symbol.h
function.o: $(hdrdir)/ruby/internal/value.h
function.o: $(hdrdir)/ruby/internal/value_type.h
@@ -854,6 +858,7 @@ handle.o: $(hdrdir)/ruby/internal/special_consts.h
handle.o: $(hdrdir)/ruby/internal/static_assert.h
handle.o: $(hdrdir)/ruby/internal/stdalign.h
handle.o: $(hdrdir)/ruby/internal/stdbool.h
+handle.o: $(hdrdir)/ruby/internal/stdckdint.h
handle.o: $(hdrdir)/ruby/internal/symbol.h
handle.o: $(hdrdir)/ruby/internal/value.h
handle.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1027,6 +1032,7 @@ memory_view.o: $(hdrdir)/ruby/internal/special_consts.h
memory_view.o: $(hdrdir)/ruby/internal/static_assert.h
memory_view.o: $(hdrdir)/ruby/internal/stdalign.h
memory_view.o: $(hdrdir)/ruby/internal/stdbool.h
+memory_view.o: $(hdrdir)/ruby/internal/stdckdint.h
memory_view.o: $(hdrdir)/ruby/internal/symbol.h
memory_view.o: $(hdrdir)/ruby/internal/value.h
memory_view.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1193,6 +1199,7 @@ pinned.o: $(hdrdir)/ruby/internal/special_consts.h
pinned.o: $(hdrdir)/ruby/internal/static_assert.h
pinned.o: $(hdrdir)/ruby/internal/stdalign.h
pinned.o: $(hdrdir)/ruby/internal/stdbool.h
+pinned.o: $(hdrdir)/ruby/internal/stdckdint.h
pinned.o: $(hdrdir)/ruby/internal/symbol.h
pinned.o: $(hdrdir)/ruby/internal/value.h
pinned.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1366,6 +1373,7 @@ pointer.o: $(hdrdir)/ruby/internal/special_consts.h
pointer.o: $(hdrdir)/ruby/internal/static_assert.h
pointer.o: $(hdrdir)/ruby/internal/stdalign.h
pointer.o: $(hdrdir)/ruby/internal/stdbool.h
+pointer.o: $(hdrdir)/ruby/internal/stdckdint.h
pointer.o: $(hdrdir)/ruby/internal/symbol.h
pointer.o: $(hdrdir)/ruby/internal/value.h
pointer.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/io/console/depend b/ext/io/console/depend
index 59ca3442c2..5b91413f38 100644
--- a/ext/io/console/depend
+++ b/ext/io/console/depend
@@ -158,6 +158,7 @@ console.o: $(hdrdir)/ruby/internal/special_consts.h
console.o: $(hdrdir)/ruby/internal/static_assert.h
console.o: $(hdrdir)/ruby/internal/stdalign.h
console.o: $(hdrdir)/ruby/internal/stdbool.h
+console.o: $(hdrdir)/ruby/internal/stdckdint.h
console.o: $(hdrdir)/ruby/internal/symbol.h
console.o: $(hdrdir)/ruby/internal/value.h
console.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/io/nonblock/depend b/ext/io/nonblock/depend
index 48384fca62..20a96f1252 100644
--- a/ext/io/nonblock/depend
+++ b/ext/io/nonblock/depend
@@ -157,6 +157,7 @@ nonblock.o: $(hdrdir)/ruby/internal/special_consts.h
nonblock.o: $(hdrdir)/ruby/internal/static_assert.h
nonblock.o: $(hdrdir)/ruby/internal/stdalign.h
nonblock.o: $(hdrdir)/ruby/internal/stdbool.h
+nonblock.o: $(hdrdir)/ruby/internal/stdckdint.h
nonblock.o: $(hdrdir)/ruby/internal/symbol.h
nonblock.o: $(hdrdir)/ruby/internal/value.h
nonblock.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/io/wait/depend b/ext/io/wait/depend
index 83cf8f94c8..70317b1497 100644
--- a/ext/io/wait/depend
+++ b/ext/io/wait/depend
@@ -158,6 +158,7 @@ wait.o: $(hdrdir)/ruby/internal/special_consts.h
wait.o: $(hdrdir)/ruby/internal/static_assert.h
wait.o: $(hdrdir)/ruby/internal/stdalign.h
wait.o: $(hdrdir)/ruby/internal/stdbool.h
+wait.o: $(hdrdir)/ruby/internal/stdckdint.h
wait.o: $(hdrdir)/ruby/internal/symbol.h
wait.o: $(hdrdir)/ruby/internal/value.h
wait.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/json/generator/depend b/ext/json/generator/depend
index 42752d1a35..f47e5f3a70 100644
--- a/ext/json/generator/depend
+++ b/ext/json/generator/depend
@@ -161,6 +161,7 @@ generator.o: $(hdrdir)/ruby/internal/special_consts.h
generator.o: $(hdrdir)/ruby/internal/static_assert.h
generator.o: $(hdrdir)/ruby/internal/stdalign.h
generator.o: $(hdrdir)/ruby/internal/stdbool.h
+generator.o: $(hdrdir)/ruby/internal/stdckdint.h
generator.o: $(hdrdir)/ruby/internal/symbol.h
generator.o: $(hdrdir)/ruby/internal/value.h
generator.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/json/parser/depend b/ext/json/parser/depend
index cb6e547d29..f3422b4f84 100644
--- a/ext/json/parser/depend
+++ b/ext/json/parser/depend
@@ -160,6 +160,7 @@ parser.o: $(hdrdir)/ruby/internal/special_consts.h
parser.o: $(hdrdir)/ruby/internal/static_assert.h
parser.o: $(hdrdir)/ruby/internal/stdalign.h
parser.o: $(hdrdir)/ruby/internal/stdbool.h
+parser.o: $(hdrdir)/ruby/internal/stdckdint.h
parser.o: $(hdrdir)/ruby/internal/symbol.h
parser.o: $(hdrdir)/ruby/internal/value.h
parser.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/monitor/depend b/ext/monitor/depend
index 38e21b3f66..bc7ead0d32 100644
--- a/ext/monitor/depend
+++ b/ext/monitor/depend
@@ -146,6 +146,7 @@ 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
diff --git a/ext/objspace/depend b/ext/objspace/depend
index aa0c5c5d7d..a02168b06a 100644
--- a/ext/objspace/depend
+++ b/ext/objspace/depend
@@ -159,6 +159,7 @@ object_tracing.o: $(hdrdir)/ruby/internal/special_consts.h
object_tracing.o: $(hdrdir)/ruby/internal/static_assert.h
object_tracing.o: $(hdrdir)/ruby/internal/stdalign.h
object_tracing.o: $(hdrdir)/ruby/internal/stdbool.h
+object_tracing.o: $(hdrdir)/ruby/internal/stdckdint.h
object_tracing.o: $(hdrdir)/ruby/internal/symbol.h
object_tracing.o: $(hdrdir)/ruby/internal/value.h
object_tracing.o: $(hdrdir)/ruby/internal/value_type.h
@@ -358,6 +359,7 @@ objspace.o: $(hdrdir)/ruby/internal/special_consts.h
objspace.o: $(hdrdir)/ruby/internal/static_assert.h
objspace.o: $(hdrdir)/ruby/internal/stdalign.h
objspace.o: $(hdrdir)/ruby/internal/stdbool.h
+objspace.o: $(hdrdir)/ruby/internal/stdckdint.h
objspace.o: $(hdrdir)/ruby/internal/symbol.h
objspace.o: $(hdrdir)/ruby/internal/value.h
objspace.o: $(hdrdir)/ruby/internal/value_type.h
@@ -569,6 +571,7 @@ objspace_dump.o: $(hdrdir)/ruby/internal/special_consts.h
objspace_dump.o: $(hdrdir)/ruby/internal/static_assert.h
objspace_dump.o: $(hdrdir)/ruby/internal/stdalign.h
objspace_dump.o: $(hdrdir)/ruby/internal/stdbool.h
+objspace_dump.o: $(hdrdir)/ruby/internal/stdckdint.h
objspace_dump.o: $(hdrdir)/ruby/internal/symbol.h
objspace_dump.o: $(hdrdir)/ruby/internal/value.h
objspace_dump.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/openssl/depend b/ext/openssl/depend
index 0d03c85b80..12c6793939 100644
--- a/ext/openssl/depend
+++ b/ext/openssl/depend
@@ -161,6 +161,7 @@ ossl.o: $(hdrdir)/ruby/internal/special_consts.h
ossl.o: $(hdrdir)/ruby/internal/static_assert.h
ossl.o: $(hdrdir)/ruby/internal/stdalign.h
ossl.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl.o: $(hdrdir)/ruby/internal/symbol.h
ossl.o: $(hdrdir)/ruby/internal/value.h
ossl.o: $(hdrdir)/ruby/internal/value_type.h
@@ -355,6 +356,7 @@ ossl_asn1.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_asn1.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_asn1.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_asn1.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_asn1.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_asn1.o: $(hdrdir)/ruby/internal/symbol.h
ossl_asn1.o: $(hdrdir)/ruby/internal/value.h
ossl_asn1.o: $(hdrdir)/ruby/internal/value_type.h
@@ -549,6 +551,7 @@ ossl_bio.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_bio.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_bio.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_bio.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_bio.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_bio.o: $(hdrdir)/ruby/internal/symbol.h
ossl_bio.o: $(hdrdir)/ruby/internal/value.h
ossl_bio.o: $(hdrdir)/ruby/internal/value_type.h
@@ -743,6 +746,7 @@ ossl_bn.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_bn.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_bn.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_bn.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_bn.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_bn.o: $(hdrdir)/ruby/internal/symbol.h
ossl_bn.o: $(hdrdir)/ruby/internal/value.h
ossl_bn.o: $(hdrdir)/ruby/internal/value_type.h
@@ -938,6 +942,7 @@ ossl_cipher.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_cipher.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_cipher.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_cipher.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_cipher.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_cipher.o: $(hdrdir)/ruby/internal/symbol.h
ossl_cipher.o: $(hdrdir)/ruby/internal/value.h
ossl_cipher.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1132,6 +1137,7 @@ ossl_config.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_config.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_config.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_config.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_config.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_config.o: $(hdrdir)/ruby/internal/symbol.h
ossl_config.o: $(hdrdir)/ruby/internal/value.h
ossl_config.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1326,6 +1332,7 @@ ossl_digest.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_digest.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_digest.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_digest.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_digest.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_digest.o: $(hdrdir)/ruby/internal/symbol.h
ossl_digest.o: $(hdrdir)/ruby/internal/value.h
ossl_digest.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1520,6 +1527,7 @@ ossl_engine.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_engine.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_engine.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_engine.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_engine.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_engine.o: $(hdrdir)/ruby/internal/symbol.h
ossl_engine.o: $(hdrdir)/ruby/internal/value.h
ossl_engine.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1714,6 +1722,7 @@ ossl_hmac.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_hmac.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_hmac.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_hmac.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_hmac.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_hmac.o: $(hdrdir)/ruby/internal/symbol.h
ossl_hmac.o: $(hdrdir)/ruby/internal/value.h
ossl_hmac.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1908,6 +1917,7 @@ ossl_kdf.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_kdf.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_kdf.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_kdf.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_kdf.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_kdf.o: $(hdrdir)/ruby/internal/symbol.h
ossl_kdf.o: $(hdrdir)/ruby/internal/value.h
ossl_kdf.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2102,6 +2112,7 @@ ossl_ns_spki.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_ns_spki.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/symbol.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/value.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2296,6 +2307,7 @@ ossl_ocsp.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_ocsp.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/symbol.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/value.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2490,6 +2502,7 @@ ossl_pkcs12.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_pkcs12.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/value.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2684,6 +2697,7 @@ ossl_pkcs7.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_pkcs7.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/value.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2878,6 +2892,7 @@ ossl_pkey.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkey.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkey.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_pkey.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkey.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkey.o: $(hdrdir)/ruby/internal/value.h
ossl_pkey.o: $(hdrdir)/ruby/internal/value_type.h
@@ -3072,6 +3087,7 @@ ossl_pkey_dh.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_pkey_dh.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/value.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/value_type.h
@@ -3266,6 +3282,7 @@ ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/value.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/value_type.h
@@ -3460,6 +3477,7 @@ ossl_pkey_ec.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_pkey_ec.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/value.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/value_type.h
@@ -3654,6 +3672,7 @@ ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/value.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/value_type.h
@@ -3848,6 +3867,7 @@ ossl_provider.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_provider.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_provider.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_provider.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_provider.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_provider.o: $(hdrdir)/ruby/internal/symbol.h
ossl_provider.o: $(hdrdir)/ruby/internal/value.h
ossl_provider.o: $(hdrdir)/ruby/internal/value_type.h
@@ -4042,6 +4062,7 @@ ossl_rand.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_rand.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_rand.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_rand.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_rand.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_rand.o: $(hdrdir)/ruby/internal/symbol.h
ossl_rand.o: $(hdrdir)/ruby/internal/value.h
ossl_rand.o: $(hdrdir)/ruby/internal/value_type.h
@@ -4236,6 +4257,7 @@ ossl_ssl.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ssl.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_ssl.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_ssl.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_ssl.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_ssl.o: $(hdrdir)/ruby/internal/symbol.h
ossl_ssl.o: $(hdrdir)/ruby/internal/value.h
ossl_ssl.o: $(hdrdir)/ruby/internal/value_type.h
@@ -4430,6 +4452,7 @@ ossl_ssl_session.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_ssl_session.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/symbol.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/value.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/value_type.h
@@ -4624,6 +4647,7 @@ ossl_ts.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ts.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_ts.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_ts.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_ts.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_ts.o: $(hdrdir)/ruby/internal/symbol.h
ossl_ts.o: $(hdrdir)/ruby/internal/value.h
ossl_ts.o: $(hdrdir)/ruby/internal/value_type.h
@@ -4818,6 +4842,7 @@ ossl_x509.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_x509.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509.o: $(hdrdir)/ruby/internal/value.h
ossl_x509.o: $(hdrdir)/ruby/internal/value_type.h
@@ -5012,6 +5037,7 @@ ossl_x509attr.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_x509attr.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/value.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/value_type.h
@@ -5206,6 +5232,7 @@ ossl_x509cert.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_x509cert.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/value.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/value_type.h
@@ -5400,6 +5427,7 @@ ossl_x509crl.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_x509crl.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/value.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/value_type.h
@@ -5594,6 +5622,7 @@ ossl_x509ext.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_x509ext.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/value.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/value_type.h
@@ -5788,6 +5817,7 @@ ossl_x509name.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509name.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509name.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509name.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_x509name.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509name.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509name.o: $(hdrdir)/ruby/internal/value.h
ossl_x509name.o: $(hdrdir)/ruby/internal/value_type.h
@@ -5982,6 +6012,7 @@ ossl_x509req.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509req.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509req.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509req.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_x509req.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509req.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509req.o: $(hdrdir)/ruby/internal/value.h
ossl_x509req.o: $(hdrdir)/ruby/internal/value_type.h
@@ -6176,6 +6207,7 @@ ossl_x509revoked.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_x509revoked.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/value.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/value_type.h
@@ -6370,6 +6402,7 @@ ossl_x509store.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509store.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509store.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509store.o: $(hdrdir)/ruby/internal/stdbool.h
+ossl_x509store.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509store.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509store.o: $(hdrdir)/ruby/internal/value.h
ossl_x509store.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb
index 68aa7bc970..216c51e3be 100644
--- a/ext/openssl/lib/openssl/buffering.rb
+++ b/ext/openssl/lib/openssl/buffering.rb
@@ -349,13 +349,18 @@ module OpenSSL::Buffering
@wbuffer << s
@wbuffer.force_encoding(Encoding::BINARY)
@sync ||= false
- if @sync or @wbuffer.size > BLOCK_SIZE
- until @wbuffer.empty?
- begin
- nwrote = syswrite(@wbuffer)
- rescue Errno::EAGAIN
- retry
+ buffer_size = @wbuffer.size
+ if @sync or buffer_size > BLOCK_SIZE
+ nwrote = 0
+ begin
+ while nwrote < buffer_size do
+ begin
+ nwrote += syswrite(@wbuffer[nwrote, buffer_size - nwrote])
+ rescue Errno::EAGAIN
+ retry
+ end
end
+ ensure
@wbuffer[0, nwrote] = ""
end
end
diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb
index 75a74a3f51..d28bf1a374 100644
--- a/ext/openssl/lib/openssl/ssl.rb
+++ b/ext/openssl/lib/openssl/ssl.rb
@@ -459,6 +459,32 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
nil
end
+ # Close the stream for reading.
+ # This method is ignored by OpenSSL as there is no reasonable way to
+ # implement it, but exists for compatibility with IO.
+ def close_read
+ # Unsupported and ignored.
+ # Just don't read any more.
+ end
+
+ # Closes the stream for writing. The behavior of this method depends on
+ # the version of OpenSSL and the TLS protocol in use.
+ #
+ # - Sends a 'close_notify' alert to the peer.
+ # - Does not wait for the peer's 'close_notify' alert in response.
+ #
+ # In TLS 1.2 and earlier:
+ # - On receipt of a 'close_notify' alert, responds with a 'close_notify'
+ # alert of its own and close down the connection immediately,
+ # discarding any pending writes.
+ #
+ # Therefore, on TLS 1.2, this method will cause the connection to be
+ # completely shut down. On TLS 1.3, the connection will remain open for
+ # reading only.
+ def close_write
+ stop
+ end
+
private
def using_anon_cipher?
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
index 71c452c88a..0533342077 100644
--- a/ext/openssl/ossl_asn1.c
+++ b/ext/openssl/ossl_asn1.c
@@ -1163,9 +1163,12 @@ ossl_asn1prim_to_der(VALUE self)
rb_jump_tag(state);
}
p0 = p1 = (unsigned char *)RSTRING_PTR(str);
- i2d_ASN1_TYPE(asn1, &p0);
+ if (i2d_ASN1_TYPE(asn1, &p0) < 0) {
+ ASN1_TYPE_free(asn1);
+ ossl_raise(eASN1Error, "i2d_ASN1_TYPE");
+ }
ASN1_TYPE_free(asn1);
- assert(p0 - p1 == alllen);
+ ossl_str_adjust(str, p0);
/* Strip header since to_der_internal() wants only the payload */
j = ASN1_get_object((const unsigned char **)&p1, &bodylen, &tag, &tc, alllen);
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index 110610e1f9..6f74c925c0 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -386,11 +386,23 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
in = (unsigned char *)RSTRING_PTR(data);
in_len = RSTRING_LEN(data);
GetCipher(self, ctx);
- out_len = in_len+EVP_CIPHER_CTX_block_size(ctx);
- if (out_len <= 0) {
+
+ /*
+ * As of OpenSSL 3.2, there is no reliable way to determine the required
+ * output buffer size for arbitrary cipher modes.
+ * https://github.com/openssl/openssl/issues/22628
+ *
+ * in_len+block_size is usually sufficient, but AES key wrap with padding
+ * ciphers require in_len+15 even though they have a block size of 8 bytes.
+ *
+ * Using EVP_MAX_BLOCK_LENGTH (32) as a safe upper bound for ciphers
+ * 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);
}
+ out_len = in_len + EVP_MAX_BLOCK_LENGTH;
if (NIL_P(str)) {
str = rb_str_new(0, out_len);
@@ -401,7 +413,7 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
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));
+ assert(out_len <= RSTRING_LEN(str));
rb_str_set_len(str, out_len);
return str;
@@ -442,8 +454,8 @@ ossl_cipher_final(VALUE self)
* call-seq:
* cipher.name -> string
*
- * Returns the name of the cipher which may differ slightly from the original
- * name provided.
+ * Returns the short name of the cipher which may differ slightly from the
+ * original name provided.
*/
static VALUE
ossl_cipher_name(VALUE self)
diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c
index 16aeeb8106..1ae26a2355 100644
--- a/ext/openssl/ossl_digest.c
+++ b/ext/openssl/ossl_digest.c
@@ -103,7 +103,8 @@ VALUE ossl_digest_update(VALUE, VALUE);
* Digest.new(string [, data]) -> Digest
*
* Creates a Digest instance based on _string_, which is either the ln
- * (long name) or sn (short name) of a supported digest algorithm.
+ * (long name) or sn (short name) of a supported digest algorithm. A list of
+ * supported algorithms can be obtained by calling OpenSSL::Digest.digests.
*
* If _data_ (a String) is given, it is used as the initial input to the
* Digest instance, i.e.
@@ -162,6 +163,32 @@ ossl_digest_copy(VALUE self, VALUE other)
return self;
}
+static void
+add_digest_name_to_ary(const OBJ_NAME *name, void *arg)
+{
+ VALUE ary = (VALUE)arg;
+ rb_ary_push(ary, rb_str_new2(name->name));
+}
+
+/*
+ * call-seq:
+ * OpenSSL::Digest.digests -> array[string...]
+ *
+ * Returns the names of all available digests in an array.
+ */
+static VALUE
+ossl_s_digests(VALUE self)
+{
+ VALUE ary;
+
+ ary = rb_ary_new();
+ OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
+ add_digest_name_to_ary,
+ (void*)ary);
+
+ return ary;
+}
+
/*
* call-seq:
* digest.reset -> self
@@ -245,7 +272,8 @@ ossl_digest_finish(int argc, VALUE *argv, VALUE self)
* call-seq:
* digest.name -> string
*
- * Returns the sn of this Digest algorithm.
+ * Returns the short name of this Digest algorithm which may differ slightly
+ * from the original name provided.
*
* === Example
* digest = OpenSSL::Digest.new('SHA512')
@@ -412,6 +440,7 @@ Init_ossl_digest(void)
rb_define_alloc_func(cDigest, ossl_digest_alloc);
+ rb_define_module_function(cDigest, "digests", ossl_s_digests, 0);
rb_define_method(cDigest, "initialize", ossl_digest_initialize, -1);
rb_define_method(cDigest, "initialize_copy", ossl_digest_copy, 1);
rb_define_method(cDigest, "reset", ossl_digest_reset, 0);
diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c
index 78dcbd667a..446df4c075 100644
--- a/ext/openssl/ossl_pkcs7.c
+++ b/ext/openssl/ossl_pkcs7.c
@@ -165,7 +165,11 @@ ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg)
out = NULL;
pkcs7 = SMIME_read_PKCS7(in, &out);
BIO_free(in);
- if(!pkcs7) ossl_raise(ePKCS7Error, NULL);
+ if (!pkcs7)
+ ossl_raise(ePKCS7Error, "Could not parse the PKCS7");
+ if (!pkcs7->d.ptr)
+ ossl_raise(ePKCS7Error, "No content in PKCS7");
+
data = out ? ossl_membio2str(out) : Qnil;
SetPKCS7(ret, pkcs7);
ossl_pkcs7_set_data(ret, data);
@@ -346,6 +350,8 @@ ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
BIO_free(in);
if (!p7)
ossl_raise(rb_eArgError, "Could not parse the PKCS7");
+ if (!p7->d.ptr)
+ ossl_raise(rb_eArgError, "No content in PKCS7");
RTYPEDDATA_DATA(self) = p7;
PKCS7_free(p7_orig);
@@ -842,6 +848,25 @@ ossl_pkcs7_to_der(VALUE self)
}
static VALUE
+ossl_pkcs7_to_text(VALUE self)
+{
+ PKCS7 *pkcs7;
+ BIO *out;
+ VALUE str;
+
+ GetPKCS7(self, pkcs7);
+ if(!(out = BIO_new(BIO_s_mem())))
+ ossl_raise(ePKCS7Error, NULL);
+ if(!PKCS7_print_ctx(out, pkcs7, 0, NULL)) {
+ BIO_free(out);
+ ossl_raise(ePKCS7Error, NULL);
+ }
+ str = ossl_membio2str(out);
+
+ return str;
+}
+
+static VALUE
ossl_pkcs7_to_pem(VALUE self)
{
PKCS7 *pkcs7;
@@ -1050,6 +1075,7 @@ Init_ossl_pkcs7(void)
rb_define_method(cPKCS7, "to_pem", ossl_pkcs7_to_pem, 0);
rb_define_alias(cPKCS7, "to_s", "to_pem");
rb_define_method(cPKCS7, "to_der", ossl_pkcs7_to_der, 0);
+ rb_define_method(cPKCS7, "to_text", ossl_pkcs7_to_text, 0);
cPKCS7Signer = rb_define_class_under(cPKCS7, "SignerInfo", rb_cObject);
rb_define_const(cPKCS7, "Signer", cPKCS7Signer);
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 9f374b65ff..d68c64d5fb 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -1958,9 +1958,11 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
else
rb_str_modify_expand(str, ilen - RSTRING_LEN(str));
}
- rb_str_set_len(str, 0);
- if (ilen == 0)
- return str;
+
+ if (ilen == 0) {
+ rb_str_set_len(str, 0);
+ return str;
+ }
VALUE io = rb_attr_get(self, id_i_io);
diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c
index f698bdc7ff..b18a86aad9 100644
--- a/ext/openssl/ossl_ts.c
+++ b/ext/openssl/ossl_ts.c
@@ -504,6 +504,25 @@ ossl_ts_req_to_der(VALUE self)
}
static VALUE
+ossl_ts_req_to_text(VALUE self)
+{
+ TS_REQ *req;
+ BIO *out;
+
+ GetTSRequest(self, req);
+
+ out = BIO_new(BIO_s_mem());
+ if (!out) ossl_raise(eTimestampError, NULL);
+
+ if (!TS_REQ_print_bio(out, req)) {
+ BIO_free(out);
+ ossl_raise(eTimestampError, NULL);
+ }
+
+ return ossl_membio2str(out);
+}
+
+static VALUE
ossl_ts_resp_alloc(VALUE klass)
{
TS_RESP *resp;
@@ -757,6 +776,25 @@ ossl_ts_resp_to_der(VALUE self)
return asn1_to_der((void *)resp, (int (*)(void *, unsigned char **))i2d_TS_RESP);
}
+static VALUE
+ossl_ts_resp_to_text(VALUE self)
+{
+ TS_RESP *resp;
+ BIO *out;
+
+ GetTSResponse(self, resp);
+
+ out = BIO_new(BIO_s_mem());
+ if (!out) ossl_raise(eTimestampError, NULL);
+
+ if (!TS_RESP_print_bio(out, resp)) {
+ BIO_free(out);
+ ossl_raise(eTimestampError, NULL);
+ }
+
+ return ossl_membio2str(out);
+}
+
/*
* Verifies a timestamp token by checking the signature, validating the
* certificate chain implied by tsa_certificate and by checking conformance to
@@ -1073,6 +1111,25 @@ ossl_ts_token_info_to_der(VALUE self)
return asn1_to_der((void *)info, (int (*)(void *, unsigned char **))i2d_TS_TST_INFO);
}
+static VALUE
+ossl_ts_token_info_to_text(VALUE self)
+{
+ TS_TST_INFO *info;
+ BIO *out;
+
+ GetTSTokenInfo(self, info);
+
+ out = BIO_new(BIO_s_mem());
+ if (!out) ossl_raise(eTimestampError, NULL);
+
+ if (!TS_TST_INFO_print_bio(out, info)) {
+ BIO_free(out);
+ ossl_raise(eTimestampError, NULL);
+ }
+
+ return ossl_membio2str(out);
+}
+
static ASN1_INTEGER *
ossl_tsfac_serial_cb(struct TS_resp_ctx *ctx, void *data)
{
@@ -1356,6 +1413,7 @@ Init_ossl_ts(void)
rb_define_method(cTimestampResponse, "token_info", ossl_ts_resp_get_token_info, 0);
rb_define_method(cTimestampResponse, "tsa_certificate", ossl_ts_resp_get_tsa_certificate, 0);
rb_define_method(cTimestampResponse, "to_der", ossl_ts_resp_to_der, 0);
+ rb_define_method(cTimestampResponse, "to_text", ossl_ts_resp_to_text, 0);
rb_define_method(cTimestampResponse, "verify", ossl_ts_resp_verify, -1);
/* Document-class: OpenSSL::Timestamp::TokenInfo
@@ -1374,6 +1432,7 @@ Init_ossl_ts(void)
rb_define_method(cTimestampTokenInfo, "ordering", ossl_ts_token_info_get_ordering, 0);
rb_define_method(cTimestampTokenInfo, "nonce", ossl_ts_token_info_get_nonce, 0);
rb_define_method(cTimestampTokenInfo, "to_der", ossl_ts_token_info_to_der, 0);
+ rb_define_method(cTimestampTokenInfo, "to_text", ossl_ts_token_info_to_text, 0);
/* Document-class: OpenSSL::Timestamp::Request
* Allows to create timestamp requests or parse existing ones. A Request is
@@ -1399,6 +1458,7 @@ Init_ossl_ts(void)
rb_define_method(cTimestampRequest, "cert_requested=", ossl_ts_req_set_cert_requested, 1);
rb_define_method(cTimestampRequest, "cert_requested?", ossl_ts_req_get_cert_requested, 0);
rb_define_method(cTimestampRequest, "to_der", ossl_ts_req_to_der, 0);
+ rb_define_method(cTimestampRequest, "to_text", ossl_ts_req_to_text, 0);
/*
* Indicates a successful response. Equal to +0+.
diff --git a/ext/pathname/depend b/ext/pathname/depend
index 5dd8b042de..cca7877dad 100644
--- a/ext/pathname/depend
+++ b/ext/pathname/depend
@@ -157,6 +157,7 @@ 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
diff --git a/ext/psych/depend b/ext/psych/depend
index 13fbe3fb19..a4d9ca9a6a 100644
--- a/ext/psych/depend
+++ b/ext/psych/depend
@@ -171,6 +171,7 @@ psych.o: $(hdrdir)/ruby/internal/special_consts.h
psych.o: $(hdrdir)/ruby/internal/static_assert.h
psych.o: $(hdrdir)/ruby/internal/stdalign.h
psych.o: $(hdrdir)/ruby/internal/stdbool.h
+psych.o: $(hdrdir)/ruby/internal/stdckdint.h
psych.o: $(hdrdir)/ruby/internal/symbol.h
psych.o: $(hdrdir)/ruby/internal/value.h
psych.o: $(hdrdir)/ruby/internal/value_type.h
@@ -347,6 +348,7 @@ psych_emitter.o: $(hdrdir)/ruby/internal/special_consts.h
psych_emitter.o: $(hdrdir)/ruby/internal/static_assert.h
psych_emitter.o: $(hdrdir)/ruby/internal/stdalign.h
psych_emitter.o: $(hdrdir)/ruby/internal/stdbool.h
+psych_emitter.o: $(hdrdir)/ruby/internal/stdckdint.h
psych_emitter.o: $(hdrdir)/ruby/internal/symbol.h
psych_emitter.o: $(hdrdir)/ruby/internal/value.h
psych_emitter.o: $(hdrdir)/ruby/internal/value_type.h
@@ -523,6 +525,7 @@ psych_parser.o: $(hdrdir)/ruby/internal/special_consts.h
psych_parser.o: $(hdrdir)/ruby/internal/static_assert.h
psych_parser.o: $(hdrdir)/ruby/internal/stdalign.h
psych_parser.o: $(hdrdir)/ruby/internal/stdbool.h
+psych_parser.o: $(hdrdir)/ruby/internal/stdckdint.h
psych_parser.o: $(hdrdir)/ruby/internal/symbol.h
psych_parser.o: $(hdrdir)/ruby/internal/value.h
psych_parser.o: $(hdrdir)/ruby/internal/value_type.h
@@ -699,6 +702,7 @@ psych_to_ruby.o: $(hdrdir)/ruby/internal/special_consts.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/static_assert.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/stdalign.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/stdbool.h
+psych_to_ruby.o: $(hdrdir)/ruby/internal/stdckdint.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/symbol.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/value.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/value_type.h
@@ -875,6 +879,7 @@ psych_yaml_tree.o: $(hdrdir)/ruby/internal/special_consts.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/static_assert.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/stdalign.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/stdbool.h
+psych_yaml_tree.o: $(hdrdir)/ruby/internal/stdckdint.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/symbol.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/value.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/pty/depend b/ext/pty/depend
index d4d0d558ef..adecfff862 100644
--- a/ext/pty/depend
+++ b/ext/pty/depend
@@ -157,6 +157,7 @@ pty.o: $(hdrdir)/ruby/internal/special_consts.h
pty.o: $(hdrdir)/ruby/internal/static_assert.h
pty.o: $(hdrdir)/ruby/internal/stdalign.h
pty.o: $(hdrdir)/ruby/internal/stdbool.h
+pty.o: $(hdrdir)/ruby/internal/stdckdint.h
pty.o: $(hdrdir)/ruby/internal/symbol.h
pty.o: $(hdrdir)/ruby/internal/value.h
pty.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/rbconfig/sizeof/depend b/ext/rbconfig/sizeof/depend
index 4e4ebd4ae5..5f75fa8c76 100644
--- a/ext/rbconfig/sizeof/depend
+++ b/ext/rbconfig/sizeof/depend
@@ -161,6 +161,7 @@ limits.o: $(hdrdir)/ruby/internal/special_consts.h
limits.o: $(hdrdir)/ruby/internal/static_assert.h
limits.o: $(hdrdir)/ruby/internal/stdalign.h
limits.o: $(hdrdir)/ruby/internal/stdbool.h
+limits.o: $(hdrdir)/ruby/internal/stdckdint.h
limits.o: $(hdrdir)/ruby/internal/symbol.h
limits.o: $(hdrdir)/ruby/internal/value.h
limits.o: $(hdrdir)/ruby/internal/value_type.h
@@ -319,6 +320,7 @@ sizes.o: $(hdrdir)/ruby/internal/special_consts.h
sizes.o: $(hdrdir)/ruby/internal/static_assert.h
sizes.o: $(hdrdir)/ruby/internal/stdalign.h
sizes.o: $(hdrdir)/ruby/internal/stdbool.h
+sizes.o: $(hdrdir)/ruby/internal/stdckdint.h
sizes.o: $(hdrdir)/ruby/internal/symbol.h
sizes.o: $(hdrdir)/ruby/internal/value.h
sizes.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/ripper/depend b/ext/ripper/depend
index 3b9b890de8..fe6bd872bd 100644
--- a/ext/ripper/depend
+++ b/ext/ripper/depend
@@ -200,6 +200,7 @@ eventids1.o: $(hdrdir)/ruby/internal/special_consts.h
eventids1.o: $(hdrdir)/ruby/internal/static_assert.h
eventids1.o: $(hdrdir)/ruby/internal/stdalign.h
eventids1.o: $(hdrdir)/ruby/internal/stdbool.h
+eventids1.o: $(hdrdir)/ruby/internal/stdckdint.h
eventids1.o: $(hdrdir)/ruby/internal/symbol.h
eventids1.o: $(hdrdir)/ruby/internal/value.h
eventids1.o: $(hdrdir)/ruby/internal/value_type.h
@@ -370,6 +371,7 @@ eventids2.o: $(hdrdir)/ruby/internal/special_consts.h
eventids2.o: $(hdrdir)/ruby/internal/static_assert.h
eventids2.o: $(hdrdir)/ruby/internal/stdalign.h
eventids2.o: $(hdrdir)/ruby/internal/stdbool.h
+eventids2.o: $(hdrdir)/ruby/internal/stdckdint.h
eventids2.o: $(hdrdir)/ruby/internal/symbol.h
eventids2.o: $(hdrdir)/ruby/internal/value.h
eventids2.o: $(hdrdir)/ruby/internal/value_type.h
@@ -549,6 +551,7 @@ ripper.o: $(hdrdir)/ruby/internal/special_consts.h
ripper.o: $(hdrdir)/ruby/internal/static_assert.h
ripper.o: $(hdrdir)/ruby/internal/stdalign.h
ripper.o: $(hdrdir)/ruby/internal/stdbool.h
+ripper.o: $(hdrdir)/ruby/internal/stdckdint.h
ripper.o: $(hdrdir)/ruby/internal/symbol.h
ripper.o: $(hdrdir)/ruby/internal/value.h
ripper.o: $(hdrdir)/ruby/internal/value_type.h
@@ -786,6 +789,7 @@ ripper_init.o: $(hdrdir)/ruby/internal/special_consts.h
ripper_init.o: $(hdrdir)/ruby/internal/static_assert.h
ripper_init.o: $(hdrdir)/ruby/internal/stdalign.h
ripper_init.o: $(hdrdir)/ruby/internal/stdbool.h
+ripper_init.o: $(hdrdir)/ruby/internal/stdckdint.h
ripper_init.o: $(hdrdir)/ruby/internal/symbol.h
ripper_init.o: $(hdrdir)/ruby/internal/value.h
ripper_init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/ripper/ripper_init.c.tmpl b/ext/ripper/ripper_init.c.tmpl
index c9d381da5b..21f29bd79a 100644
--- a/ext/ripper/ripper_init.c.tmpl
+++ b/ext/ripper/ripper_init.c.tmpl
@@ -17,15 +17,40 @@
ID id_warn, id_warning, id_gets, id_assoc;
+enum lex_type {
+ lex_type_str,
+ lex_type_io,
+ lex_type_generic,
+};
+
struct ripper {
rb_parser_t *p;
+ enum lex_type type;
+ union {
+ struct lex_pointer_string ptr_str;
+ VALUE val;
+ } data;
};
static void
ripper_parser_mark2(void *ptr)
{
struct ripper *r = (struct ripper*)ptr;
- if (r->p) ripper_parser_mark(r->p);
+ if (r->p) {
+ ripper_parser_mark(r->p);
+
+ switch (r->type) {
+ case lex_type_str:
+ rb_gc_mark(r->data.ptr_str.str);
+ break;
+ case lex_type_io:
+ rb_gc_mark(r->data.val);
+ break;
+ case lex_type_generic:
+ rb_gc_mark(r->data.val);
+ break;
+ }
+ }
}
static void
@@ -53,16 +78,18 @@ static const rb_data_type_t parser_data_type = {
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
-static VALUE
-ripper_lex_get_generic(struct parser_params *p, VALUE src)
+static rb_parser_string_t *
+ripper_lex_get_generic(struct parser_params *p, rb_parser_input_data input, int line_count)
{
+ VALUE src = (VALUE)input;
VALUE line = rb_funcallv_public(src, id_gets, 0, 0);
- if (!NIL_P(line) && !RB_TYPE_P(line, T_STRING)) {
+ if (NIL_P(line)) return 0;
+ if (!RB_TYPE_P(line, T_STRING)) {
rb_raise(rb_eTypeError,
"gets returned %"PRIsVALUE" (expected String or nil)",
rb_obj_class(line));
}
- return line;
+ return rb_str_to_parser_string(p, line);
}
void
@@ -78,10 +105,19 @@ ripper_compile_error(struct parser_params *p, const char *fmt, ...)
ripper_error(p);
}
-static VALUE
-ripper_lex_io_get(struct parser_params *p, VALUE src)
+static rb_parser_string_t *
+ripper_lex_io_get(struct parser_params *p, rb_parser_input_data input, int line_count)
{
- return rb_io_gets(src);
+ VALUE src = (VALUE)input;
+ VALUE line = rb_io_gets(src);
+ if (NIL_P(line)) return 0;
+ return rb_str_to_parser_string(p, line);
+}
+
+static rb_parser_string_t *
+ripper_lex_get_str(struct parser_params *p, rb_parser_input_data input, int line_count)
+{
+ return rb_parser_lex_get_str(p, (struct lex_pointer_string *)input);
}
static VALUE
@@ -155,7 +191,7 @@ ripper_parser_encoding(VALUE vparser)
{
struct parser_params *p = ripper_parser_params(vparser, false);
- return rb_ruby_parser_encoding(p);
+ return rb_enc_from_encoding(rb_ruby_parser_encoding(p));
}
/*
@@ -294,26 +330,38 @@ parser_dedent_string(VALUE self, VALUE input, VALUE width)
static VALUE
ripper_initialize(int argc, VALUE *argv, VALUE self)
{
+ struct ripper *r;
struct parser_params *p;
VALUE src, fname, lineno;
- VALUE (*gets)(struct parser_params*,VALUE);
- VALUE input, sourcefile_string;
+ rb_parser_lex_gets_func *gets;
+ VALUE sourcefile_string;
const char *sourcefile;
int sourceline;
+ rb_parser_input_data input;
p = ripper_parser_params(self, false);
+ TypedData_Get_Struct(self, struct ripper, &parser_data_type, r);
rb_scan_args(argc, argv, "12", &src, &fname, &lineno);
if (RB_TYPE_P(src, T_FILE)) {
gets = ripper_lex_io_get;
+ r->type = lex_type_io;
+ r->data.val = src;
+ input = (rb_parser_input_data)src;
}
else if (rb_respond_to(src, id_gets)) {
gets = ripper_lex_get_generic;
+ r->type = lex_type_generic;
+ r->data.val = src;
+ input = (rb_parser_input_data)src;
}
else {
StringValue(src);
- gets = rb_ruby_ripper_lex_get_str;
+ gets = ripper_lex_get_str;
+ r->type = lex_type_str;
+ r->data.ptr_str.str = src;
+ r->data.ptr_str.ptr = 0;
+ input = (rb_parser_input_data)&r->data.ptr_str;
}
- input = src;
if (NIL_P(fname)) {
fname = STR_NEW2("(ripper)");
OBJ_FREEZE(fname);
diff --git a/ext/ripper/tools/dsl.rb b/ext/ripper/tools/dsl.rb
index 3e368813e5..d0002d1ec3 100644
--- a/ext/ripper/tools/dsl.rb
+++ b/ext/ripper/tools/dsl.rb
@@ -20,6 +20,12 @@ class DSL
NAME_PATTERN = /(?>\$|\d+|[a-zA-Z_][a-zA-Z0-9_]*|\[[a-zA-Z_.][-a-zA-Z0-9_.]*\])(?>(?:\.|->)[a-zA-Z_][a-zA-Z0-9_]*)*/.source
NOT_REF_PATTERN = /(?>\#.*|[^\"$@]*|"(?>\\.|[^\"])*")/.source
+ def self.line?(line, lineno = nil)
+ if %r</\*% *ripper(?:\[(.*?)\])?: *(.*?) *%\*/> =~ line
+ new($2, $1&.split(",") || [], lineno)
+ end
+ end
+
def initialize(code, options, lineno = nil)
@lineno = lineno
@events = {}
diff --git a/ext/ripper/tools/generate.rb b/ext/ripper/tools/generate.rb
index 27aa53bce0..92ced37f04 100644
--- a/ext/ripper/tools/generate.rb
+++ b/ext/ripper/tools/generate.rb
@@ -167,15 +167,13 @@ require_relative "dsl"
def read_ids1_with_locations(path)
h = {}
File.open(path) {|f|
- f.each.with_index(1) do |line, i|
+ f.each do |line|
next if /\A\#\s*define\s+dispatch/ =~ line
next if /ripper_dispatch/ =~ line
line.scan(/\bdispatch(\d)\((\w+)/) do |arity, event|
(h[event] ||= []).push [f.lineno, arity.to_i]
end
- if line =~ %r</\*% *ripper(?:\[(.*?)\])?: *(.*?) *%\*/>
- gen = DSL.new($2, ($1 || "").split(","), i)
- gen.generate
+ if gen = DSL.line?(line, f.lineno)
gen.events.each do |event, arity|
(h[event] ||= []).push [f.lineno, arity.to_i]
end
diff --git a/ext/ripper/tools/preproc.rb b/ext/ripper/tools/preproc.rb
index a54302fb91..a92be93d5b 100644
--- a/ext/ripper/tools/preproc.rb
+++ b/ext/ripper/tools/preproc.rb
@@ -51,47 +51,50 @@ def process(f, out, path, template)
usercode f, out, path, template
end
-def prelude(f, out)
- @exprs = {}
+require_relative 'dsl'
+
+def generate_line(f, out)
while line = f.gets
- case line
- when /\A%%/
+ case
+ when gen = DSL.line?(line)
+ out << gen.generate << "\n"
+ when line.start_with?("%%")
out << "%%\n"
- return
+ break
else
- if (/^enum lex_state_(?:bits|e) \{/ =~ line)..(/^\}/ =~ line)
- case line
- when /^\s*(EXPR_\w+),\s+\/\*(.+)\*\//
- @exprs[$1.chomp("_bit")] = $2.strip
- when /^\s*(EXPR_\w+)\s+=\s+(.+)$/
- name = $1
- val = $2.chomp(",")
- @exprs[name] = "equals to " + (val.start_with?("(") ? "<tt>#{val}</tt>" : "+#{val}+")
- end
- end
+ out << yield(line)
end
- out << line
end
end
-require_relative "dsl"
+def prelude(f, out)
+ @exprs = {}
+ generate_line(f, out) do |line|
+ if (/^enum lex_state_(?:bits|e) \{/ =~ line)..(/^\}/ =~ line)
+ case line
+ when /^\s*(EXPR_\w+),\s+\/\*(.+)\*\//
+ @exprs[$1.chomp("_bit")] = $2.strip
+ when /^\s*(EXPR_\w+)\s+=\s+(.+)$/
+ name = $1
+ val = $2.chomp(",")
+ @exprs[name] = "equals to " + (val.start_with?("(") ? "<tt>#{val}</tt>" : "+#{val}+")
+ end
+ end
+ line
+ end
+end
def grammar(f, out)
- while line = f.gets
+ generate_line(f, out) do |line|
case line
- when %r</\*% *ripper(?:\[(.*?)\])?: *(.*?) *%\*/>
- out << DSL.new($2, ($1 || "").split(",")).generate << "\n"
when %r</\*%%%\*/>
- out << "#if 0\n"
+ "#if 0\n"
when %r</\*%>
- out << "#endif\n"
+ "#endif\n"
when %r<%\*/>
- out << "\n"
- when /\A%%/
- out << "%%\n"
- return
+ "\n"
else
- out << line
+ line
end
end
end
diff --git a/ext/socket/depend b/ext/socket/depend
index e95555ea92..750bb0734f 100644
--- a/ext/socket/depend
+++ b/ext/socket/depend
@@ -170,6 +170,7 @@ ancdata.o: $(hdrdir)/ruby/internal/special_consts.h
ancdata.o: $(hdrdir)/ruby/internal/static_assert.h
ancdata.o: $(hdrdir)/ruby/internal/stdalign.h
ancdata.o: $(hdrdir)/ruby/internal/stdbool.h
+ancdata.o: $(hdrdir)/ruby/internal/stdckdint.h
ancdata.o: $(hdrdir)/ruby/internal/symbol.h
ancdata.o: $(hdrdir)/ruby/internal/value.h
ancdata.o: $(hdrdir)/ruby/internal/value_type.h
@@ -380,6 +381,7 @@ basicsocket.o: $(hdrdir)/ruby/internal/special_consts.h
basicsocket.o: $(hdrdir)/ruby/internal/static_assert.h
basicsocket.o: $(hdrdir)/ruby/internal/stdalign.h
basicsocket.o: $(hdrdir)/ruby/internal/stdbool.h
+basicsocket.o: $(hdrdir)/ruby/internal/stdckdint.h
basicsocket.o: $(hdrdir)/ruby/internal/symbol.h
basicsocket.o: $(hdrdir)/ruby/internal/value.h
basicsocket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -590,6 +592,7 @@ constants.o: $(hdrdir)/ruby/internal/special_consts.h
constants.o: $(hdrdir)/ruby/internal/static_assert.h
constants.o: $(hdrdir)/ruby/internal/stdalign.h
constants.o: $(hdrdir)/ruby/internal/stdbool.h
+constants.o: $(hdrdir)/ruby/internal/stdckdint.h
constants.o: $(hdrdir)/ruby/internal/symbol.h
constants.o: $(hdrdir)/ruby/internal/value.h
constants.o: $(hdrdir)/ruby/internal/value_type.h
@@ -801,6 +804,7 @@ ifaddr.o: $(hdrdir)/ruby/internal/special_consts.h
ifaddr.o: $(hdrdir)/ruby/internal/static_assert.h
ifaddr.o: $(hdrdir)/ruby/internal/stdalign.h
ifaddr.o: $(hdrdir)/ruby/internal/stdbool.h
+ifaddr.o: $(hdrdir)/ruby/internal/stdckdint.h
ifaddr.o: $(hdrdir)/ruby/internal/symbol.h
ifaddr.o: $(hdrdir)/ruby/internal/value.h
ifaddr.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1011,6 +1015,7 @@ 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
@@ -1221,6 +1226,7 @@ ipsocket.o: $(hdrdir)/ruby/internal/special_consts.h
ipsocket.o: $(hdrdir)/ruby/internal/static_assert.h
ipsocket.o: $(hdrdir)/ruby/internal/stdalign.h
ipsocket.o: $(hdrdir)/ruby/internal/stdbool.h
+ipsocket.o: $(hdrdir)/ruby/internal/stdckdint.h
ipsocket.o: $(hdrdir)/ruby/internal/symbol.h
ipsocket.o: $(hdrdir)/ruby/internal/value.h
ipsocket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1431,6 +1437,7 @@ option.o: $(hdrdir)/ruby/internal/special_consts.h
option.o: $(hdrdir)/ruby/internal/static_assert.h
option.o: $(hdrdir)/ruby/internal/stdalign.h
option.o: $(hdrdir)/ruby/internal/stdbool.h
+option.o: $(hdrdir)/ruby/internal/stdckdint.h
option.o: $(hdrdir)/ruby/internal/symbol.h
option.o: $(hdrdir)/ruby/internal/value.h
option.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1641,6 +1648,7 @@ raddrinfo.o: $(hdrdir)/ruby/internal/special_consts.h
raddrinfo.o: $(hdrdir)/ruby/internal/static_assert.h
raddrinfo.o: $(hdrdir)/ruby/internal/stdalign.h
raddrinfo.o: $(hdrdir)/ruby/internal/stdbool.h
+raddrinfo.o: $(hdrdir)/ruby/internal/stdckdint.h
raddrinfo.o: $(hdrdir)/ruby/internal/symbol.h
raddrinfo.o: $(hdrdir)/ruby/internal/value.h
raddrinfo.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1851,6 +1859,7 @@ socket.o: $(hdrdir)/ruby/internal/special_consts.h
socket.o: $(hdrdir)/ruby/internal/static_assert.h
socket.o: $(hdrdir)/ruby/internal/stdalign.h
socket.o: $(hdrdir)/ruby/internal/stdbool.h
+socket.o: $(hdrdir)/ruby/internal/stdckdint.h
socket.o: $(hdrdir)/ruby/internal/symbol.h
socket.o: $(hdrdir)/ruby/internal/value.h
socket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2061,6 +2070,7 @@ sockssocket.o: $(hdrdir)/ruby/internal/special_consts.h
sockssocket.o: $(hdrdir)/ruby/internal/static_assert.h
sockssocket.o: $(hdrdir)/ruby/internal/stdalign.h
sockssocket.o: $(hdrdir)/ruby/internal/stdbool.h
+sockssocket.o: $(hdrdir)/ruby/internal/stdckdint.h
sockssocket.o: $(hdrdir)/ruby/internal/symbol.h
sockssocket.o: $(hdrdir)/ruby/internal/value.h
sockssocket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2271,6 +2281,7 @@ tcpserver.o: $(hdrdir)/ruby/internal/special_consts.h
tcpserver.o: $(hdrdir)/ruby/internal/static_assert.h
tcpserver.o: $(hdrdir)/ruby/internal/stdalign.h
tcpserver.o: $(hdrdir)/ruby/internal/stdbool.h
+tcpserver.o: $(hdrdir)/ruby/internal/stdckdint.h
tcpserver.o: $(hdrdir)/ruby/internal/symbol.h
tcpserver.o: $(hdrdir)/ruby/internal/value.h
tcpserver.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2481,6 +2492,7 @@ tcpsocket.o: $(hdrdir)/ruby/internal/special_consts.h
tcpsocket.o: $(hdrdir)/ruby/internal/static_assert.h
tcpsocket.o: $(hdrdir)/ruby/internal/stdalign.h
tcpsocket.o: $(hdrdir)/ruby/internal/stdbool.h
+tcpsocket.o: $(hdrdir)/ruby/internal/stdckdint.h
tcpsocket.o: $(hdrdir)/ruby/internal/symbol.h
tcpsocket.o: $(hdrdir)/ruby/internal/value.h
tcpsocket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2691,6 +2703,7 @@ udpsocket.o: $(hdrdir)/ruby/internal/special_consts.h
udpsocket.o: $(hdrdir)/ruby/internal/static_assert.h
udpsocket.o: $(hdrdir)/ruby/internal/stdalign.h
udpsocket.o: $(hdrdir)/ruby/internal/stdbool.h
+udpsocket.o: $(hdrdir)/ruby/internal/stdckdint.h
udpsocket.o: $(hdrdir)/ruby/internal/symbol.h
udpsocket.o: $(hdrdir)/ruby/internal/value.h
udpsocket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2901,6 +2914,7 @@ unixserver.o: $(hdrdir)/ruby/internal/special_consts.h
unixserver.o: $(hdrdir)/ruby/internal/static_assert.h
unixserver.o: $(hdrdir)/ruby/internal/stdalign.h
unixserver.o: $(hdrdir)/ruby/internal/stdbool.h
+unixserver.o: $(hdrdir)/ruby/internal/stdckdint.h
unixserver.o: $(hdrdir)/ruby/internal/symbol.h
unixserver.o: $(hdrdir)/ruby/internal/value.h
unixserver.o: $(hdrdir)/ruby/internal/value_type.h
@@ -3111,6 +3125,7 @@ unixsocket.o: $(hdrdir)/ruby/internal/special_consts.h
unixsocket.o: $(hdrdir)/ruby/internal/static_assert.h
unixsocket.o: $(hdrdir)/ruby/internal/stdalign.h
unixsocket.o: $(hdrdir)/ruby/internal/stdbool.h
+unixsocket.o: $(hdrdir)/ruby/internal/stdckdint.h
unixsocket.o: $(hdrdir)/ruby/internal/symbol.h
unixsocket.o: $(hdrdir)/ruby/internal/value.h
unixsocket.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/stringio/depend b/ext/stringio/depend
index ba2b812041..b9fba7e9fa 100644
--- a/ext/stringio/depend
+++ b/ext/stringio/depend
@@ -157,6 +157,7 @@ stringio.o: $(hdrdir)/ruby/internal/special_consts.h
stringio.o: $(hdrdir)/ruby/internal/static_assert.h
stringio.o: $(hdrdir)/ruby/internal/stdalign.h
stringio.o: $(hdrdir)/ruby/internal/stdbool.h
+stringio.o: $(hdrdir)/ruby/internal/stdckdint.h
stringio.o: $(hdrdir)/ruby/internal/symbol.h
stringio.o: $(hdrdir)/ruby/internal/value.h
stringio.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/strscan/depend b/ext/strscan/depend
index 8d985b59e8..8dbae206d4 100644
--- a/ext/strscan/depend
+++ b/ext/strscan/depend
@@ -157,6 +157,7 @@ strscan.o: $(hdrdir)/ruby/internal/special_consts.h
strscan.o: $(hdrdir)/ruby/internal/static_assert.h
strscan.o: $(hdrdir)/ruby/internal/stdalign.h
strscan.o: $(hdrdir)/ruby/internal/stdbool.h
+strscan.o: $(hdrdir)/ruby/internal/stdckdint.h
strscan.o: $(hdrdir)/ruby/internal/symbol.h
strscan.o: $(hdrdir)/ruby/internal/value.h
strscan.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/win32/lib/win32/registry.rb b/ext/win32/lib/win32/registry.rb
index 16a08310ad..92b95d1bf7 100644
--- a/ext/win32/lib/win32/registry.rb
+++ b/ext/win32/lib/win32/registry.rb
@@ -1,4 +1,4 @@
-# frozen_string_literal: false
+# frozen_string_literal: true
require 'fiddle/import'
module Win32
@@ -254,30 +254,34 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
/^(?:x64|x86_64)/ =~ RUBY_PLATFORM
end
+ TEMPLATE_HANDLE = 'J<'
+
def packhandle(h)
- win64? ? packqw(h) : packdw(h)
+ [h].pack(TEMPLATE_HANDLE)
end
def unpackhandle(h)
- win64? ? unpackqw(h) : unpackdw(h)
+ (h + [0].pack(TEMPLATE_HANDLE)).unpack1(TEMPLATE_HANDLE)
end
+ TEMPLATE_DWORD = 'V'
+
def packdw(dw)
- [dw].pack('V')
+ [dw].pack(TEMPLATE_DWORD)
end
def unpackdw(dw)
- dw += [0].pack('V')
- dw.unpack('V')[0]
+ (dw + [0].pack(TEMPLATE_DWORD)).unpack1(TEMPLATE_DWORD)
end
+ TEMPLATE_QWORD = 'Q<'
+
def packqw(qw)
- [ qw & 0xFFFFFFFF, qw >> 32 ].pack('VV')
+ [qw].pack(TEMPLATE_QWORD)
end
def unpackqw(qw)
- qw = qw.unpack('VV')
- (qw[1] << 32) | qw[0]
+ (qw + [0].pack(TEMPLATE_QWORD)).unpack1(TEMPLATE_QWORD)
end
def make_wstr(str)
@@ -318,7 +322,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
size = packdw(0)
name = make_wstr(name)
check RegQueryValueExW.call(hkey, name, 0, type, 0, size)
- data = "\0".force_encoding('ASCII-8BIT') * unpackdw(size)
+ data = "\0".b * unpackdw(size)
check RegQueryValueExW.call(hkey, name, 0, type, data, size)
[ unpackdw(type), data[0, unpackdw(size)] ]
end
@@ -373,8 +377,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
def self.expand_environ(str)
str.gsub(Regexp.compile("%([^%]+)%".encode(str.encoding))) {
v = $1.encode(LOCALE)
- (e = ENV[v] || ENV[v.upcase]; e.encode(str.encoding) if e) ||
- $&
+ (ENV[v] || ENV[v.upcase])&.encode(str.encoding) || $&
}
end
@@ -384,7 +387,6 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
REG_RESOURCE_LIST REG_FULL_RESOURCE_DESCRIPTOR
REG_RESOURCE_REQUIREMENTS_LIST REG_QWORD
].inject([]) do |ary, type|
- type.freeze
ary[Constants.const_get(type)] = type
ary
end.freeze
@@ -657,7 +659,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
when REG_DWORD
[ type, API.unpackdw(data) ]
when REG_DWORD_BIG_ENDIAN
- [ type, data.unpack('N')[0] ]
+ [ type, data.unpack1('N') ]
when REG_QWORD
[ type, API.unpackqw(data) ]
else
diff --git a/ext/zlib/depend b/ext/zlib/depend
index bdcf6a93e8..bdce420264 100644
--- a/ext/zlib/depend
+++ b/ext/zlib/depend
@@ -157,6 +157,7 @@ zlib.o: $(hdrdir)/ruby/internal/special_consts.h
zlib.o: $(hdrdir)/ruby/internal/static_assert.h
zlib.o: $(hdrdir)/ruby/internal/stdalign.h
zlib.o: $(hdrdir)/ruby/internal/stdbool.h
+zlib.o: $(hdrdir)/ruby/internal/stdckdint.h
zlib.o: $(hdrdir)/ruby/internal/symbol.h
zlib.o: $(hdrdir)/ruby/internal/value.h
zlib.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index fe03072576..aad9f8d28a 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -90,7 +90,7 @@ static void zstream_expand_buffer_into(struct zstream*, unsigned long);
static int zstream_expand_buffer_non_stream(struct zstream *z);
static void zstream_append_buffer(struct zstream*, const Bytef*, long);
static VALUE zstream_detach_buffer(struct zstream*);
-static VALUE zstream_shift_buffer(struct zstream*, long);
+static VALUE zstream_shift_buffer(struct zstream*, long, VALUE);
static void zstream_buffer_ungets(struct zstream*, const Bytef*, unsigned long);
static void zstream_buffer_ungetbyte(struct zstream*, int);
static void zstream_append_input(struct zstream*, const Bytef*, long);
@@ -170,8 +170,8 @@ static void gzfile_check_footer(struct gzfile*, VALUE outbuf);
static void gzfile_write(struct gzfile*, Bytef*, long);
static long gzfile_read_more(struct gzfile*, VALUE outbuf);
static void gzfile_calc_crc(struct gzfile*, VALUE);
-static VALUE gzfile_read(struct gzfile*, long);
-static VALUE gzfile_read_all(struct gzfile*);
+static VALUE gzfile_read(struct gzfile*, long, VALUE);
+static VALUE gzfile_read_all(struct gzfile*, VALUE);
static void gzfile_ungets(struct gzfile*, const Bytef*, long);
static void gzfile_ungetbyte(struct gzfile*, int);
static VALUE gzfile_writer_end_run(VALUE);
@@ -820,19 +820,31 @@ zstream_detach_buffer(struct zstream *z)
}
static VALUE
-zstream_shift_buffer(struct zstream *z, long len)
+zstream_shift_buffer(struct zstream *z, long len, VALUE dst)
{
- VALUE dst;
char *bufptr;
long buflen = ZSTREAM_BUF_FILLED(z);
if (buflen <= len) {
- return zstream_detach_buffer(z);
+ if (NIL_P(dst) || (!ZSTREAM_IS_FINISHED(z) && !ZSTREAM_IS_GZFILE(z) &&
+ rb_block_given_p())) {
+ return zstream_detach_buffer(z);
+ } else {
+ bufptr = RSTRING_PTR(z->buf);
+ rb_str_resize(dst, buflen);
+ memcpy(RSTRING_PTR(dst), bufptr, buflen);
+ }
+ buflen = 0;
+ } else {
+ bufptr = RSTRING_PTR(z->buf);
+ if (NIL_P(dst)) {
+ dst = rb_str_new(bufptr, len);
+ } else {
+ rb_str_resize(dst, len);
+ memcpy(RSTRING_PTR(dst), bufptr, len);
+ }
+ buflen -= len;
}
-
- bufptr = RSTRING_PTR(z->buf);
- dst = rb_str_new(bufptr, len);
- buflen -= len;
memmove(bufptr, bufptr + len, buflen);
rb_str_set_len(z->buf, buflen);
z->stream.next_out = (Bytef*)RSTRING_END(z->buf);
@@ -2874,18 +2886,18 @@ gzfile_newstr(struct gzfile *gz, VALUE str)
}
static long
-gzfile_fill(struct gzfile *gz, long len)
+gzfile_fill(struct gzfile *gz, long len, VALUE outbuf)
{
if (len < 0)
rb_raise(rb_eArgError, "negative length %ld given", len);
if (len == 0)
return 0;
while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) < len) {
- gzfile_read_more(gz, Qnil);
+ gzfile_read_more(gz, outbuf);
}
if (GZFILE_IS_FINISHED(gz)) {
if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
- gzfile_check_footer(gz, Qnil);
+ gzfile_check_footer(gz, outbuf);
}
return -1;
}
@@ -2893,14 +2905,27 @@ gzfile_fill(struct gzfile *gz, long len)
}
static VALUE
-gzfile_read(struct gzfile *gz, long len)
+gzfile_read(struct gzfile *gz, long len, VALUE outbuf)
{
VALUE dst;
- len = gzfile_fill(gz, len);
- if (len == 0) return rb_str_new(0, 0);
- if (len < 0) return Qnil;
- dst = zstream_shift_buffer(&gz->z, len);
+ len = gzfile_fill(gz, len, outbuf);
+
+ if (len < 0) {
+ if (!NIL_P(outbuf))
+ rb_str_resize(outbuf, 0);
+ return Qnil;
+ }
+ if (len == 0) {
+ if (NIL_P(outbuf))
+ return rb_str_new(0, 0);
+ else {
+ rb_str_resize(outbuf, 0);
+ return outbuf;
+ }
+ }
+
+ dst = zstream_shift_buffer(&gz->z, len, outbuf);
if (!NIL_P(dst)) gzfile_calc_crc(gz, dst);
return dst;
}
@@ -2933,29 +2958,26 @@ gzfile_readpartial(struct gzfile *gz, long len, VALUE outbuf)
rb_raise(rb_eEOFError, "end of file reached");
}
- dst = zstream_shift_buffer(&gz->z, len);
+ dst = zstream_shift_buffer(&gz->z, len, outbuf);
gzfile_calc_crc(gz, dst);
- if (!NIL_P(outbuf)) {
- rb_str_resize(outbuf, RSTRING_LEN(dst));
- memcpy(RSTRING_PTR(outbuf), RSTRING_PTR(dst), RSTRING_LEN(dst));
- dst = outbuf;
- }
return dst;
}
static VALUE
-gzfile_read_all(struct gzfile *gz)
+gzfile_read_all(struct gzfile *gz, VALUE dst)
{
- VALUE dst;
-
while (!ZSTREAM_IS_FINISHED(&gz->z)) {
- gzfile_read_more(gz, Qnil);
+ gzfile_read_more(gz, dst);
}
if (GZFILE_IS_FINISHED(gz)) {
if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
- gzfile_check_footer(gz, Qnil);
+ gzfile_check_footer(gz, dst);
}
+ if (!NIL_P(dst)) {
+ rb_str_resize(dst, 0);
+ return dst;
+ }
return rb_str_new(0, 0);
}
@@ -2993,7 +3015,7 @@ gzfile_getc(struct gzfile *gz)
de = (unsigned char *)ds + GZFILE_CBUF_CAPA;
(void)rb_econv_convert(gz->ec, &sp, se, &dp, de, ECONV_PARTIAL_INPUT|ECONV_AFTER_OUTPUT);
rb_econv_check_error(gz->ec);
- dst = zstream_shift_buffer(&gz->z, sp - ss);
+ dst = zstream_shift_buffer(&gz->z, sp - ss, Qnil);
gzfile_calc_crc(gz, dst);
rb_str_resize(cbuf, dp - ds);
return cbuf;
@@ -3001,7 +3023,7 @@ gzfile_getc(struct gzfile *gz)
else {
buf = gz->z.buf;
len = rb_enc_mbclen(RSTRING_PTR(buf), RSTRING_END(buf), gz->enc);
- dst = gzfile_read(gz, len);
+ dst = gzfile_read(gz, len, Qnil);
if (NIL_P(dst)) return dst;
return gzfile_newstr(gz, dst);
}
@@ -3909,7 +3931,7 @@ rb_gzreader_s_zcat(int argc, VALUE *argv, VALUE klass)
if (!buf) {
buf = rb_str_new(0, 0);
}
- tmpbuf = gzfile_read_all(get_gzfile(obj));
+ tmpbuf = gzfile_read_all(get_gzfile(obj), Qnil);
rb_str_cat(buf, RSTRING_PTR(tmpbuf), RSTRING_LEN(tmpbuf));
}
@@ -4011,19 +4033,19 @@ static VALUE
rb_gzreader_read(int argc, VALUE *argv, VALUE obj)
{
struct gzfile *gz = get_gzfile(obj);
- VALUE vlen;
+ VALUE vlen, outbuf;
long len;
- rb_scan_args(argc, argv, "01", &vlen);
+ rb_scan_args(argc, argv, "02", &vlen, &outbuf);
if (NIL_P(vlen)) {
- return gzfile_read_all(gz);
+ return gzfile_read_all(gz, outbuf);
}
len = NUM2INT(vlen);
if (len < 0) {
rb_raise(rb_eArgError, "negative length %ld given", len);
}
- return gzfile_read(gz, len);
+ return gzfile_read(gz, len, outbuf);
}
/*
@@ -4096,7 +4118,7 @@ rb_gzreader_getbyte(VALUE obj)
struct gzfile *gz = get_gzfile(obj);
VALUE dst;
- dst = gzfile_read(gz, 1);
+ dst = gzfile_read(gz, 1, Qnil);
if (!NIL_P(dst)) {
dst = INT2FIX((unsigned int)(RSTRING_PTR(dst)[0]) & 0xff);
}
@@ -4217,7 +4239,7 @@ gzreader_skip_linebreaks(struct gzfile *gz)
}
}
- str = zstream_shift_buffer(&gz->z, n - 1);
+ str = zstream_shift_buffer(&gz->z, n - 1, Qnil);
gzfile_calc_crc(gz, str);
}
@@ -4238,7 +4260,7 @@ gzreader_charboundary(struct gzfile *gz, long n)
if (l < n) {
int n_bytes = rb_enc_precise_mbclen(p, e, gz->enc);
if (MBCLEN_NEEDMORE_P(n_bytes)) {
- if ((l = gzfile_fill(gz, n + MBCLEN_NEEDMORE_LEN(n_bytes))) > 0) {
+ if ((l = gzfile_fill(gz, n + MBCLEN_NEEDMORE_LEN(n_bytes), Qnil)) > 0) {
return l;
}
}
@@ -4290,10 +4312,10 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
if (NIL_P(rs)) {
if (limit < 0) {
- dst = gzfile_read_all(gz);
+ dst = gzfile_read_all(gz, Qnil);
if (RSTRING_LEN(dst) == 0) return Qnil;
}
- else if ((n = gzfile_fill(gz, limit)) <= 0) {
+ else if ((n = gzfile_fill(gz, limit, Qnil)) <= 0) {
return Qnil;
}
else {
@@ -4303,7 +4325,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
else {
n = limit;
}
- dst = zstream_shift_buffer(&gz->z, n);
+ dst = zstream_shift_buffer(&gz->z, n, Qnil);
if (NIL_P(dst)) return dst;
gzfile_calc_crc(gz, dst);
dst = gzfile_newstr(gz, dst);
@@ -4330,7 +4352,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
while (ZSTREAM_BUF_FILLED(&gz->z) < rslen) {
if (ZSTREAM_IS_FINISHED(&gz->z)) {
if (ZSTREAM_BUF_FILLED(&gz->z) > 0) gz->lineno++;
- return gzfile_read(gz, rslen);
+ return gzfile_read(gz, rslen, Qnil);
}
gzfile_read_more(gz, Qnil);
}
@@ -4367,7 +4389,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
}
gz->lineno++;
- dst = gzfile_read(gz, n);
+ dst = gzfile_read(gz, n, Qnil);
if (NIL_P(dst)) return dst;
if (rspara) {
gzreader_skip_linebreaks(gz);
diff --git a/gc.c b/gc.c
index 057d6998f6..474454e487 100644
--- a/gc.c
+++ b/gc.c
@@ -224,6 +224,9 @@ size_add_overflow(size_t x, size_t y)
bool p;
#if 0
+#elif defined(ckd_add)
+ p = ckd_add(&z, x, y);
+
#elif __has_builtin(__builtin_add_overflow)
p = __builtin_add_overflow(x, y, &z);
@@ -416,7 +419,6 @@ rb_gc_guarded_ptr_val(volatile VALUE *ptr, VALUE val)
#endif
#define USE_TICK_T (PRINT_ENTER_EXIT_TICK || PRINT_MEASURE_LINE || PRINT_ROOT_TICKS)
-#define TICK_TYPE 1
typedef struct {
size_t size_pool_init_slots[SIZE_POOL_COUNT];
@@ -687,29 +689,33 @@ typedef struct RVALUE {
VALUE v3;
} values;
} as;
+} RVALUE;
- /* Start of RVALUE_OVERHEAD.
- * Do not directly read these members from the RVALUE as they're located
- * at the end of the slot (which may differ in size depending on the size
- * pool). */
-#if RACTOR_CHECK_MODE
+/* These members ae located at the end of the slot that the object is in. */
+#if RACTOR_CHECK_MODE || GC_DEBUG
+struct rvalue_overhead {
+# if RACTOR_CHECK_MODE
uint32_t _ractor_belonging_id;
-#endif
-#if GC_DEBUG
+# endif
+# if GC_DEBUG
const char *file;
int line;
-#endif
-} RVALUE;
+# endif
+};
-#if RACTOR_CHECK_MODE
-# define RVALUE_OVERHEAD (sizeof(RVALUE) - offsetof(RVALUE, _ractor_belonging_id))
-#elif GC_DEBUG
-# define RVALUE_OVERHEAD (sizeof(RVALUE) - offsetof(RVALUE, file))
+// Make sure that RVALUE_OVERHEAD aligns to sizeof(VALUE)
+# define RVALUE_OVERHEAD (sizeof(struct { \
+ union { \
+ struct rvalue_overhead overhead; \
+ VALUE value; \
+ }; \
+}))
+# define GET_RVALUE_OVERHEAD(obj) ((struct rvalue_overhead *)((uintptr_t)obj + rb_gc_obj_slot_size(obj)))
#else
# define RVALUE_OVERHEAD 0
#endif
-STATIC_ASSERT(sizeof_rvalue, sizeof(RVALUE) == (SIZEOF_VALUE * 5) + RVALUE_OVERHEAD);
+STATIC_ASSERT(sizeof_rvalue, sizeof(RVALUE) == (SIZEOF_VALUE * 5));
STATIC_ASSERT(alignof_rvalue, RUBY_ALIGNOF(RVALUE) == SIZEOF_VALUE);
typedef uintptr_t bits_t;
@@ -717,7 +723,6 @@ enum {
BITS_SIZE = sizeof(bits_t),
BITS_BITLENGTH = ( BITS_SIZE * CHAR_BIT )
};
-#define popcount_bits rb_popcount_intptr
struct heap_page_header {
struct heap_page *page;
@@ -954,7 +959,7 @@ typedef struct rb_objspace {
#define HEAP_PAGE_ALIGN_LOG 16
#endif
-#define BASE_SLOT_SIZE sizeof(RVALUE)
+#define BASE_SLOT_SIZE (sizeof(RVALUE) + RVALUE_OVERHEAD)
#define CEILDIV(i, mod) roomof(i, mod)
enum {
@@ -1292,6 +1297,7 @@ total_freed_objects(rb_objspace_t *objspace)
#define gc_mode(objspace) gc_mode_verify((enum gc_mode)(objspace)->flags.mode)
#define gc_mode_set(objspace, m) ((objspace)->flags.mode = (unsigned int)gc_mode_verify(m))
+#define gc_needs_major_flags objspace->rgengc.need_major_gc
#define is_marking(objspace) (gc_mode(objspace) == gc_mode_marking)
#define is_sweeping(objspace) (gc_mode(objspace) == gc_mode_sweeping)
@@ -1416,17 +1422,7 @@ static const char *obj_type_name(VALUE obj);
static void gc_finalize_deferred(void *dmy);
-/*
- * 1 - TSC (H/W Time Stamp Counter)
- * 2 - getrusage
- */
-#ifndef TICK_TYPE
-#define TICK_TYPE 1
-#endif
-
#if USE_TICK_T
-
-#if TICK_TYPE == 1
/* the following code is only for internal tuning. */
/* Source code to use RDTSC is quoted and modified from
@@ -1523,28 +1519,6 @@ tick(void)
return clock();
}
#endif /* TSC */
-
-#elif TICK_TYPE == 2
-typedef double tick_t;
-#define PRItick "4.9f"
-
-static inline tick_t
-tick(void)
-{
- return getrusage_time();
-}
-#else /* TICK_TYPE */
-#error "choose tick type"
-#endif /* TICK_TYPE */
-
-#define MEASURE_LINE(expr) do { \
- volatile tick_t start_time = tick(); \
- volatile tick_t end_time; \
- expr; \
- end_time = tick(); \
- fprintf(stderr, "0\t%"PRItick"\t%s\n", end_time - start_time, #expr); \
-} while (0)
-
#else /* USE_TICK_T */
#define MEASURE_LINE(expr) expr
#endif /* USE_TICK_T */
@@ -1882,44 +1856,45 @@ rb_gc_initial_stress_set(VALUE flag)
initial_stress = flag;
}
-static void * Alloc_GC_impl(void);
+static void *rb_gc_impl_objspace_alloc(void);
#if USE_SHARED_GC
# include "dln.h"
-# define Alloc_GC rb_gc_functions->init
+
+# define RUBY_GC_LIBRARY_PATH "RUBY_GC_LIBRARY_PATH"
void
-ruby_external_gc_init()
+ruby_external_gc_init(void)
{
- rb_gc_function_map_t *map = malloc(sizeof(rb_gc_function_map_t));
- rb_gc_functions = map;
-
- char *gc_so_path = getenv("RUBY_GC_LIBRARY_PATH");
- if (!gc_so_path) {
- map->init = Alloc_GC_impl;
- return;
+ char *gc_so_path = getenv(RUBY_GC_LIBRARY_PATH);
+ void *handle = NULL;
+ if (gc_so_path && dln_supported_p()) {
+ char error[1024];
+ handle = dln_open(gc_so_path, error, sizeof(error));
+ if (!handle) {
+ fprintf(stderr, "%s", error);
+ rb_bug("ruby_external_gc_init: Shared library %s cannot be opened", gc_so_path);
+ }
}
- void *h = dln_open(gc_so_path);
- if (!h) {
- rb_bug(
- "ruby_external_gc_init: Shared library %s cannot be opened.",
- gc_so_path
- );
- }
+# define load_external_gc_func(name) do { \
+ if (handle) { \
+ rb_gc_functions->name = dln_symbol(handle, "rb_gc_impl_" #name); \
+ if (!rb_gc_functions->name) { \
+ rb_bug("ruby_external_gc_init: " #name " func not exported by library %s", gc_so_path); \
+ } \
+ } \
+ else { \
+ rb_gc_functions->name = rb_gc_impl_##name; \
+ } \
+} while (0)
- void *gc_init_func = dln_symbol(h, "Init_GC");
- if (!gc_init_func) {
- rb_bug(
- "ruby_external_gc_init: Init_GC func not exported by library %s",
- gc_so_path
- );
- }
+ load_external_gc_func(objspace_alloc);
- map->init = gc_init_func;
+# undef load_external_gc_func
}
-#else
-# define Alloc_GC Alloc_GC_impl
+
+# define rb_gc_impl_objspace_alloc rb_gc_functions->objspace_alloc
#endif
rb_objspace_t *
@@ -1928,9 +1903,13 @@ rb_objspace_alloc(void)
#if USE_SHARED_GC
ruby_external_gc_init();
#endif
- return (rb_objspace_t *)Alloc_GC();
+ return (rb_objspace_t *)rb_gc_impl_objspace_alloc();
}
+#if USE_SHARED_GC
+# undef rb_gc_impl_objspace_alloc
+#endif
+
static void free_stack_chunks(mark_stack_t *);
static void mark_stack_free_cache(mark_stack_t *);
static void heap_page_free(rb_objspace_t *objspace, struct heap_page *page);
@@ -2550,7 +2529,7 @@ heap_prepare(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap
* sweeping and still don't have a free page, then
* gc_sweep_finish_size_pool should allow us to create a new page. */
if (heap->free_pages == NULL && !heap_increment(objspace, size_pool, heap)) {
- if (objspace->rgengc.need_major_gc == GPR_FLAG_NONE) {
+ if (gc_needs_major_flags == GPR_FLAG_NONE) {
rb_bug("cannot create a new page after GC");
}
else { // Major GC is required, which will allow us to create new page
@@ -2659,7 +2638,7 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace,
#endif
#if GC_DEBUG
- RANY(obj)->file = rb_source_location_cstr(&RANY(obj)->line);
+ GET_RVALUE_OVERHEAD(obj)->file = rb_source_location_cstr(&GET_RVALUE_OVERHEAD(obj)->line);
GC_ASSERT(!SPECIAL_CONST_P(obj)); /* check alignment */
#endif
@@ -2692,12 +2671,6 @@ size_pool_slot_size(unsigned char pool_id)
return slot_size;
}
-size_t
-rb_size_pool_slot_size(unsigned char pool_id)
-{
- return size_pool_slot_size(pool_id);
-}
-
bool
rb_gc_size_allocatable_p(size_t size)
{
@@ -2711,7 +2684,7 @@ rb_gc_size_pool_sizes(void)
{
if (size_pool_sizes[0] == 0) {
for (unsigned char i = 0; i < SIZE_POOL_COUNT; i++) {
- size_pool_sizes[i] = rb_size_pool_slot_size(i);
+ size_pool_sizes[i] = size_pool_slot_size(i);
}
}
@@ -3507,7 +3480,7 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
}
-#define OBJ_ID_INCREMENT (sizeof(RVALUE))
+#define OBJ_ID_INCREMENT (BASE_SLOT_SIZE)
#define OBJ_ID_INITIAL (OBJ_ID_INCREMENT)
static int
@@ -3537,7 +3510,7 @@ static const struct st_hash_type object_id_hash_type = {
};
static void *
-Alloc_GC_impl(void)
+rb_gc_impl_objspace_alloc(void)
{
rb_objspace_t *objspace = calloc1(sizeof(rb_objspace_t));
ruby_current_vm_ptr->objspace = objspace;
@@ -5632,7 +5605,7 @@ gc_sweep_finish_size_pool(rb_objspace_t *objspace, rb_size_pool_t *size_pool)
grow_heap = TRUE;
}
else if (is_growth_heap) { /* Only growth heaps are allowed to start a major GC. */
- objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_NOFREE;
+ gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_NOFREE;
size_pool->force_major_gc_count++;
}
}
@@ -8071,7 +8044,7 @@ gc_marks_finish(rb_objspace_t *objspace)
}
else {
gc_report(1, objspace, "gc_marks_finish: next is full GC!!)\n");
- objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_NOFREE;
+ gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_NOFREE;
}
}
}
@@ -8087,20 +8060,20 @@ gc_marks_finish(rb_objspace_t *objspace)
}
if (objspace->rgengc.uncollectible_wb_unprotected_objects > objspace->rgengc.uncollectible_wb_unprotected_objects_limit) {
- objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_SHADY;
+ gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_SHADY;
}
if (objspace->rgengc.old_objects > objspace->rgengc.old_objects_limit) {
- objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_OLDGEN;
+ gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_OLDGEN;
}
if (RGENGC_FORCE_MAJOR_GC) {
- objspace->rgengc.need_major_gc = GPR_FLAG_MAJOR_BY_FORCE;
+ gc_needs_major_flags = GPR_FLAG_MAJOR_BY_FORCE;
}
gc_report(1, objspace, "gc_marks_finish (marks %"PRIdSIZE" objects, "
"old %"PRIdSIZE" objects, total %"PRIdSIZE" slots, "
"sweep %"PRIdSIZE" slots, increment: %"PRIdSIZE", next GC: %s)\n",
objspace->marked_slots, objspace->rgengc.old_objects, heap_eden_total_slots(objspace), sweep_slots, heap_allocatable_pages(objspace),
- objspace->rgengc.need_major_gc ? "major" : "minor");
+ gc_needs_major_flags ? "major" : "minor");
}
rb_ractor_finish_marking();
@@ -8225,7 +8198,7 @@ gc_compact_plane(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *
do {
VALUE vp = (VALUE)p;
- GC_ASSERT(vp % sizeof(RVALUE) == 0);
+ GC_ASSERT(vp % BASE_SLOT_SIZE == 0);
if (bitset & 1) {
objspace->rcompactor.considered_count_table[BUILTIN_TYPE(vp)]++;
@@ -8942,7 +8915,7 @@ gc_reset_malloc_info(rb_objspace_t *objspace, bool full_mark)
#if RGENGC_ESTIMATE_OLDMALLOC
if (!full_mark) {
if (objspace->rgengc.oldmalloc_increase > objspace->rgengc.oldmalloc_increase_limit) {
- objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_OLDMALLOC;
+ 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);
@@ -8953,7 +8926,7 @@ 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",
rb_gc_count(),
- objspace->rgengc.need_major_gc,
+ gc_needs_major_flags,
objspace->rgengc.oldmalloc_increase,
objspace->rgengc.oldmalloc_increase_limit,
gc_params.oldmalloc_limit_max);
@@ -9029,8 +9002,8 @@ gc_start(rb_objspace_t *objspace, unsigned int reason)
objspace->flags.immediate_sweep = !(flag & (1<<gc_stress_no_immediate_sweep));
}
- if (objspace->rgengc.need_major_gc) {
- reason |= objspace->rgengc.need_major_gc;
+ if (gc_needs_major_flags) {
+ reason |= gc_needs_major_flags;
do_full_mark = TRUE;
}
else if (RGENGC_FORCE_MAJOR_GC) {
@@ -9038,7 +9011,7 @@ gc_start(rb_objspace_t *objspace, unsigned int reason)
do_full_mark = TRUE;
}
- objspace->rgengc.need_major_gc = GPR_FLAG_NONE;
+ gc_needs_major_flags = GPR_FLAG_NONE;
if (do_full_mark && (reason & GPR_FLAG_MAJOR_MASK) == 0) {
reason |= GPR_FLAG_MAJOR_BY_FORCE; /* GC by CAPI, METHOD, and so on. */
@@ -9296,7 +9269,7 @@ gc_enter(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_
gc_enter_count(event);
if (UNLIKELY(during_gc != 0)) rb_bug("during_gc != 0");
- if (RGENGC_CHECK_MODE >= 3) gc_verify_internal_consistency(objspace);
+ if (RGENGC_CHECK_MODE >= 3 && (dont_gc_val() == 0)) gc_verify_internal_consistency(objspace);
during_gc = TRUE;
RUBY_DEBUG_LOG("%s (%s)",gc_enter_event_cstr(event), gc_current_status(objspace));
@@ -9983,9 +9956,6 @@ update_cc_tbl_i(VALUE ccs_ptr, void *data)
}
for (int i=0; i<ccs->len; i++) {
- if (gc_object_moved_p(objspace, (VALUE)ccs->entries[i].ci)) {
- ccs->entries[i].ci = (struct rb_callinfo *)rb_gc_location((VALUE)ccs->entries[i].ci);
- }
if (gc_object_moved_p(objspace, (VALUE)ccs->entries[i].cc)) {
ccs->entries[i].cc = (struct rb_callcache *)rb_gc_location((VALUE)ccs->entries[i].cc);
}
@@ -10766,7 +10736,7 @@ gc_info_decode(rb_objspace_t *objspace, const VALUE hash_or_key, const unsigned
SET(major_by, major_by);
if (orig_flags == 0) { /* set need_major_by only if flags not set explicitly */
- unsigned int need_major_flags = objspace->rgengc.need_major_gc;
+ unsigned int need_major_flags = gc_needs_major_flags;
need_major_by =
(need_major_flags & GPR_FLAG_MAJOR_BY_NOFREE) ? sym_nofree :
(need_major_flags & GPR_FLAG_MAJOR_BY_OLDGEN) ? sym_oldgen :
@@ -11895,7 +11865,7 @@ static inline void *
objspace_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size)
{
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) {}
#if CALC_EXACT_MALLOC_SIZE
{
@@ -12369,6 +12339,38 @@ ruby_mimmalloc(size_t size)
return mem;
}
+void *
+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)) {
+ return NULL;
+ }
+ size = t.right + sizeof(struct malloc_obj_info);
+ mem = calloc1(size);
+ if (!mem) {
+ return NULL;
+ }
+ else
+ /* set 0 for consistency of allocated_size/allocations */
+ {
+ struct malloc_obj_info *info = mem;
+ info->size = 0;
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+ info->gen = 0;
+ info->file = NULL;
+ info->line = 0;
+#endif
+ mem = info + 1;
+ }
+#else
+ mem = calloc(num, size);
+#endif
+ return mem;
+}
+
void
ruby_mimfree(void *ptr)
{
@@ -13182,7 +13184,7 @@ rb_raw_obj_info_common(char *const buff, const size_t buff_size, const VALUE obj
}
#if GC_DEBUG
- APPEND_F("@%s:%d", RANY(obj)->file, RANY(obj)->line);
+ APPEND_F("@%s:%d", GET_RVALUE_OVERHEAD(obj)->file, GET_RVALUE_OVERHEAD(obj)->line);
#endif
}
end:
@@ -13491,7 +13493,7 @@ rb_gcdebug_print_obj_condition(VALUE obj)
{
rb_objspace_t *objspace = &rb_objspace;
- fprintf(stderr, "created at: %s:%d\n", RANY(obj)->file, RANY(obj)->line);
+ fprintf(stderr, "created at: %s:%d\n", GET_RVALUE_OVERHEAD(obj)->file, GET_RVALUE_OVERHEAD(obj)->line);
if (BUILTIN_TYPE(obj) == T_MOVED) {
fprintf(stderr, "moved?: true\n");
@@ -13516,7 +13518,7 @@ rb_gcdebug_print_obj_condition(VALUE obj)
if (is_lazy_sweeping(objspace)) {
fprintf(stderr, "lazy sweeping?: true\n");
- fprintf(stderr, "page swept?: %s\n", GET_HEAP_PAGE(ptr)->flags.before_sweep ? "false" : "true");
+ fprintf(stderr, "page swept?: %s\n", GET_HEAP_PAGE(obj)->flags.before_sweep ? "false" : "true");
}
else {
fprintf(stderr, "lazy sweeping?: false\n");
@@ -13592,10 +13594,9 @@ rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
* traverse all living objects with an iterator.
*
* ObjectSpace also provides support for object finalizers, procs that will be
- * called when a specific object is about to be destroyed by garbage
- * collection. See the documentation for
- * <code>ObjectSpace.define_finalizer</code> for important information on
- * how to use this method correctly.
+ * called after a specific object was destroyed by garbage collection. See
+ * the documentation for +ObjectSpace.define_finalizer+ for important
+ * information on how to use this method correctly.
*
* a = "A"
* b = "B"
@@ -13635,6 +13636,12 @@ rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
void
Init_GC(void)
{
+#if USE_SHARED_GC
+ if (getenv(RUBY_GC_LIBRARY_PATH) != NULL && !dln_supported_p()) {
+ rb_warn(RUBY_GC_LIBRARY_PATH " is ignored because this executable file can't load extension libraries");
+ }
+#endif
+
#undef rb_intern
malloc_offset = gc_compute_malloc_offset();
@@ -13648,7 +13655,7 @@ Init_GC(void)
rb_hash_aset(gc_constants, ID2SYM(rb_intern("DEBUG")), RBOOL(GC_DEBUG));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("BASE_SLOT_SIZE")), SIZET2NUM(BASE_SLOT_SIZE - RVALUE_OVERHEAD));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OVERHEAD")), SIZET2NUM(RVALUE_OVERHEAD));
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(sizeof(RVALUE)));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(BASE_SLOT_SIZE));
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));
diff --git a/gems/bundled_gems b/gems/bundled_gems
index ad979c1c5c..bb6dcb5447 100644
--- a/gems/bundled_gems
+++ b/gems/bundled_gems
@@ -6,14 +6,14 @@
# - revision: revision in repository-url to test
# if `revision` is not given, "v"+`version` or `version` will be used.
-minitest 5.22.3 https://github.com/minitest/minitest ea9caafc0754b1d6236a490d59e624b53209734a
+minitest 5.23.0 https://github.com/minitest/minitest
power_assert 2.0.3 https://github.com/ruby/power_assert 84e85124c5014a139af39161d484156cfe87a9ed
rake 13.2.1 https://github.com/ruby/rake
test-unit 3.6.2 https://github.com/test-unit/test-unit
rexml 3.2.6 https://github.com/ruby/rexml
rss 0.3.0 https://github.com/ruby/rss
net-ftp 0.3.4 https://github.com/ruby/net-ftp
-net-imap 0.4.10 https://github.com/ruby/net-imap
+net-imap 0.4.11 https://github.com/ruby/net-imap
net-pop 0.1.2 https://github.com/ruby/net-pop
net-smtp 0.5.0 https://github.com/ruby/net-smtp
matrix 0.4.2 https://github.com/ruby/matrix
@@ -25,7 +25,7 @@ racc 1.7.3 https://github.com/ruby/racc
mutex_m 0.2.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.7 https://github.com/ruby/bigdecimal
+bigdecimal 3.1.8 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
diff --git a/hrtime.h b/hrtime.h
index 7ed4e6b04c..2ca7b0c088 100644
--- a/hrtime.h
+++ b/hrtime.h
@@ -6,6 +6,8 @@
# include <sys/time.h>
#endif
+#include "internal/compilers.h"
+
/*
* Hi-res monotonic clock. It is currently nsec resolution, which has over
* 500 years of range (with an unsigned 64-bit integer). Developers
@@ -61,7 +63,11 @@ rb_hrtime_mul(rb_hrtime_t a, rb_hrtime_t b)
{
rb_hrtime_t c;
-#ifdef HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW
+#ifdef ckd_mul
+ if (ckd_mul(&c, a, b))
+ return RB_HRTIME_MAX;
+
+#elif __has_builtin(__builtin_mul_overflow)
if (__builtin_mul_overflow(a, b, &c))
return RB_HRTIME_MAX;
#else
@@ -81,7 +87,11 @@ rb_hrtime_add(rb_hrtime_t a, rb_hrtime_t b)
{
rb_hrtime_t c;
-#ifdef HAVE_BUILTIN___BUILTIN_ADD_OVERFLOW
+#ifdef ckd_add
+ if (ckd_add(&c, a, b))
+ return RB_HRTIME_MAX;
+
+#elif __has_builtin(__builtin_add_overflow)
if (__builtin_add_overflow(a, b, &c))
return RB_HRTIME_MAX;
#else
diff --git a/imemo.c b/imemo.c
index 8403859146..1face1ce4e 100644
--- a/imemo.c
+++ b/imemo.c
@@ -130,7 +130,7 @@ rb_imemo_memsize(VALUE obj)
size_t size = 0;
switch (imemo_type(obj)) {
case imemo_ast:
- size += rb_ast_memsize((rb_ast_t *)obj);
+ rb_bug("imemo_ast is obsolete");
break;
case imemo_callcache:
@@ -196,7 +196,6 @@ cc_table_mark_i(ID id, VALUE ccs_ptr, void *data)
VM_ASSERT((VALUE)data == 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].ci);
rb_gc_mark_movable((VALUE)ccs->entries[i].cc);
}
return ID_TABLE_CONTINUE;
@@ -274,7 +273,7 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
{
switch (imemo_type(obj)) {
case imemo_ast:
- // TODO: Make AST decoupled from IMEMO
+ rb_bug("imemo_ast is obsolete");
break;
case imemo_callcache: {
@@ -514,8 +513,7 @@ rb_imemo_free(VALUE obj)
{
switch (imemo_type(obj)) {
case imemo_ast:
- rb_ast_free((rb_ast_t *)obj);
- RB_DEBUG_COUNTER_INC(obj_imemo_ast);
+ rb_bug("imemo_ast is obsolete");
break;
case imemo_callcache:
diff --git a/include/ruby/internal/encoding/encoding.h b/include/ruby/internal/encoding/encoding.h
index dc3e0151f0..a680651a81 100644
--- a/include/ruby/internal/encoding/encoding.h
+++ b/include/ruby/internal/encoding/encoding.h
@@ -28,6 +28,7 @@
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/attr/returns_nonnull.h"
#include "ruby/internal/dllexport.h"
+#include "ruby/internal/encoding/coderange.h"
#include "ruby/internal/value.h"
#include "ruby/internal/core/rbasic.h"
#include "ruby/internal/fl_type.h"
diff --git a/include/ruby/internal/memory.h b/include/ruby/internal/memory.h
index 3bd54cd6c7..270cc1ac8b 100644
--- a/include/ruby/internal/memory.h
+++ b/include/ruby/internal/memory.h
@@ -56,6 +56,7 @@
#include "ruby/internal/has/builtin.h"
#include "ruby/internal/stdalign.h"
#include "ruby/internal/stdbool.h"
+#include "ruby/internal/stdckdint.h"
#include "ruby/internal/xmalloc.h"
#include "ruby/backward/2/limits.h"
#include "ruby/backward/2/long_long.h"
@@ -567,7 +568,10 @@ rbimpl_size_mul_overflow(size_t x, size_t y)
{
struct rbimpl_size_mul_overflow_tag ret = { false, 0, };
-#if RBIMPL_HAS_BUILTIN(__builtin_mul_overflow)
+#if defined(ckd_mul)
+ ret.left = ckd_mul(&ret.right, x, y);
+
+#elif RBIMPL_HAS_BUILTIN(__builtin_mul_overflow)
ret.left = __builtin_mul_overflow(x, y, &ret.right);
#elif defined(DSIZE_T)
diff --git a/include/ruby/internal/stdckdint.h b/include/ruby/internal/stdckdint.h
new file mode 100644
index 0000000000..e5b5b8b751
--- /dev/null
+++ b/include/ruby/internal/stdckdint.h
@@ -0,0 +1,68 @@
+#ifndef RBIMPL_STDCKDINT_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_STDCKDINT_H
+/**
+ * @author Ruby developers <ruby-core@ruby-lang.org>
+ * @copyright This file is a part of the programming language Ruby.
+ * Permission is hereby granted, to either redistribute and/or
+ * modify this file, provided that the conditions mentioned in the
+ * file COPYING are met. Consult the file for details.
+ * @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 C23 shim for <stdckdint.h>
+ */
+#include "ruby/internal/config.h"
+#include "ruby/internal/cast.h"
+#include "ruby/internal/has/builtin.h"
+#include "ruby/internal/stdbool.h"
+
+#ifdef __has_include
+# if __has_include(<stdckdint.h>)
+# /* Conforming C23 situation; e.g. recent clang */
+# define RBIMPL_HAVE_STDCKDINT_H
+# endif
+#endif
+
+#ifdef HAVE_STDCKDINT_H
+# /* Some OSes (most notably FreeBSD) have this file. */
+# define RBIMPL_HAVE_STDCKDINT_H
+#endif
+
+#ifdef __cplusplus
+# /* It seems OS/Compiler provided stdckdint.h tend not support C++ yet.
+# * Situations could improve someday but in a meantime let us work around.
+# */
+# undef RBIMPL_HAVE_STDCKDINT_H
+#endif
+
+#ifdef RBIMPL_HAVE_STDCKDINT_H
+# /* Take that. */
+# include <stdckdint.h>
+
+#elif RBIMPL_HAS_BUILTIN(__builtin_add_overflow)
+# define ckd_add(x, y, z) RBIMPL_CAST((bool)__builtin_add_overflow((y), (z), (x)))
+# define ckd_sub(x, y, z) RBIMPL_CAST((bool)__builtin_sub_overflow((y), (z), (x)))
+# define ckd_mul(x, y, z) RBIMPL_CAST((bool)__builtin_mul_overflow((y), (z), (x)))
+# define __STDC_VERSION_STDCKDINT_H__ 202311L
+
+#/* elif defined(__cplusplus) */
+#/* :TODO: if we assume C++11 we can use `<type_traits>` to implement them. */
+
+#else
+# /* intentionally leave them undefined */
+# /* to make `#ifdef ckd_add` etc. work as intended. */
+# undef ckd_add
+# undef ckd_sub
+# undef ckd_mul
+# undef __STDC_VERSION_STDCKDINT_H__
+#endif
+
+#endif /* RBIMPL_STDCKDINT_H */
diff --git a/include/ruby/io/buffer.h b/include/ruby/io/buffer.h
index b044db0539..e4d98bf051 100644
--- a/include/ruby/io/buffer.h
+++ b/include/ruby/io/buffer.h
@@ -69,14 +69,10 @@ enum rb_io_buffer_endian {
RB_IO_BUFFER_LITTLE_ENDIAN = 4,
RB_IO_BUFFER_BIG_ENDIAN = 8,
-#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_LITTLE_ENDIAN,
-#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#if defined(WORDS_BIGENDIAN)
RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_BIG_ENDIAN,
-#elif defined(REG_DWORD) && REG_DWORD == REG_DWORD_LITTLE_ENDIAN
+#else
RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_LITTLE_ENDIAN,
-#elif defined(REG_DWORD) && REG_DWORD == REG_DWORD_BIG_ENDIAN
- RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_BIG_ENDIAN,
#endif
RB_IO_BUFFER_NETWORK_ENDIAN = RB_IO_BUFFER_BIG_ENDIAN
diff --git a/internal/encoding.h b/internal/encoding.h
index 11ffa6d83d..fe9ea10ec4 100644
--- a/internal/encoding.h
+++ b/internal/encoding.h
@@ -18,6 +18,7 @@
/* encoding.c */
ID rb_id_encoding(void);
+const char * rb_enc_inspect_name(rb_encoding *enc);
rb_encoding *rb_enc_get_from_index(int index);
rb_encoding *rb_enc_check_str(VALUE str1, VALUE str2);
int rb_encdb_replicate(const char *alias, const char *orig);
diff --git a/internal/gc.h b/internal/gc.h
index 91dbc0ccf3..ecc3f11b2c 100644
--- a/internal/gc.h
+++ b/internal/gc.h
@@ -119,8 +119,6 @@ int ruby_get_stack_grow_direction(volatile VALUE *addr);
const char *rb_obj_info(VALUE obj);
const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj);
-size_t rb_size_pool_slot_size(unsigned char pool_id);
-
struct rb_execution_context_struct; /* in vm_core.h */
struct rb_objspace; /* in vm_core.h */
@@ -195,6 +193,7 @@ typedef struct ractor_newobj_cache {
/* gc.c */
extern int ruby_disable_gc;
RUBY_ATTR_MALLOC void *ruby_mimmalloc(size_t size);
+RUBY_ATTR_MALLOC void *ruby_mimcalloc(size_t num, size_t size);
void ruby_mimfree(void *ptr);
void rb_gc_prepare_heap(void);
void rb_objspace_set_event_hook(const rb_event_flag_t event);
diff --git a/internal/imemo.h b/internal/imemo.h
index 673e7e668a..36c0776987 100644
--- a/internal/imemo.h
+++ b/internal/imemo.h
@@ -39,7 +39,7 @@ enum imemo_type {
imemo_ment = 6,
imemo_iseq = 7,
imemo_tmpbuf = 8,
- imemo_ast = 9,
+ imemo_ast = 9, // Obsolete due to the universal parser
imemo_parser_strterm = 10,
imemo_callinfo = 11,
imemo_callcache = 12,
diff --git a/internal/parse.h b/internal/parse.h
index 80328686c1..5f52e8a8e3 100644
--- a/internal/parse.h
+++ b/internal/parse.h
@@ -13,7 +13,7 @@
#include "internal/static_assert.h"
#ifdef UNIVERSAL_PARSER
-#define rb_encoding void
+#define rb_encoding const void
#endif
struct rb_iseq_struct; /* in vm_core.h */
@@ -53,14 +53,13 @@ void rb_ruby_parser_set_options(rb_parser_t *p, int print, int loop, int chomp,
rb_parser_t *rb_ruby_parser_set_context(rb_parser_t *p, const struct rb_iseq_struct *base, int main);
void rb_ruby_parser_set_script_lines(rb_parser_t *p);
void rb_ruby_parser_error_tolerant(rb_parser_t *p);
-rb_ast_t* rb_ruby_parser_compile_file_path(rb_parser_t *p, VALUE fname, VALUE file, int start);
void rb_ruby_parser_keep_tokens(rb_parser_t *p);
-rb_ast_t* rb_ruby_parser_compile_generic(rb_parser_t *p, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int start);
-rb_ast_t* rb_ruby_parser_compile_string_path(rb_parser_t *p, VALUE f, VALUE s, int line);
+typedef rb_parser_string_t*(rb_parser_lex_gets_func)(struct parser_params*, rb_parser_input_data, int);
+rb_ast_t *rb_parser_compile(rb_parser_t *p, rb_parser_lex_gets_func *gets, const char *fname_ptr, long fname_len, rb_encoding *fname_enc, rb_parser_input_data input, int line);
RUBY_SYMBOL_EXPORT_BEGIN
-VALUE rb_ruby_parser_encoding(rb_parser_t *p);
+rb_encoding *rb_ruby_parser_encoding(rb_parser_t *p);
int rb_ruby_parser_end_seen_p(rb_parser_t *p);
int rb_ruby_parser_set_yydebug(rb_parser_t *p, int flag);
rb_parser_string_t *rb_str_to_parser_string(rb_parser_t *p, VALUE str);
@@ -73,6 +72,11 @@ int rb_parser_local_defined(struct parser_params *p, ID id, const struct rb_iseq
RUBY_SYMBOL_EXPORT_END
+#ifndef UNIVERSAL_PARSER
+rb_parser_t *rb_ruby_parser_allocate(void);
+rb_parser_t *rb_ruby_parser_new(void);
+#endif
+
#ifdef RIPPER
void ripper_parser_mark(void *ptr);
void ripper_parser_free(void *ptr);
@@ -86,7 +90,7 @@ VALUE rb_ruby_parser_debug_output(rb_parser_t *p);
void rb_ruby_parser_set_debug_output(rb_parser_t *p, VALUE output);
VALUE rb_ruby_parser_parsing_thread(rb_parser_t *p);
void rb_ruby_parser_set_parsing_thread(rb_parser_t *p, VALUE parsing_thread);
-void rb_ruby_parser_ripper_initialize(rb_parser_t *p, VALUE (*gets)(struct parser_params*,VALUE), VALUE input, VALUE sourcefile_string, const char *sourcefile, int sourceline);
+void rb_ruby_parser_ripper_initialize(rb_parser_t *p, rb_parser_lex_gets_func *gets, rb_parser_input_data input, VALUE sourcefile_string, const char *sourcefile, int sourceline);
VALUE rb_ruby_parser_result(rb_parser_t *p);
rb_encoding *rb_ruby_parser_enc(rb_parser_t *p);
VALUE rb_ruby_parser_ruby_sourcefile_string(rb_parser_t *p);
@@ -94,7 +98,6 @@ int rb_ruby_parser_ruby_sourceline(rb_parser_t *p);
int rb_ruby_parser_lex_state(rb_parser_t *p);
void rb_ruby_ripper_parse0(rb_parser_t *p);
int rb_ruby_ripper_dedent_string(rb_parser_t *p, VALUE string, int width);
-VALUE rb_ruby_ripper_lex_get_str(rb_parser_t *p, VALUE s);
int rb_ruby_ripper_initialized_p(rb_parser_t *p);
void rb_ruby_ripper_parser_initialize(rb_parser_t *p);
long rb_ruby_ripper_column(rb_parser_t *p);
diff --git a/internal/ruby_parser.h b/internal/ruby_parser.h
index f0cec86668..8e306d18de 100644
--- a/internal/ruby_parser.h
+++ b/internal/ruby_parser.h
@@ -5,21 +5,27 @@
#include "internal/bignum.h"
#include "internal/compilers.h"
#include "internal/complex.h"
+#include "internal/parse.h"
#include "internal/rational.h"
#include "rubyparser.h"
#include "vm.h"
+struct lex_pointer_string {
+ VALUE str;
+ long ptr;
+};
+
RUBY_SYMBOL_EXPORT_BEGIN
#ifdef UNIVERSAL_PARSER
const rb_parser_config_t *rb_ruby_parser_config(void);
-rb_parser_t *rb_parser_params_allocate(void);
rb_parser_t *rb_parser_params_new(void);
#endif
VALUE rb_parser_set_context(VALUE, const struct rb_iseq_struct *, int);
VALUE rb_parser_new(void);
-rb_ast_t *rb_parser_compile_string_path(VALUE vparser, VALUE fname, VALUE src, int line);
+VALUE rb_parser_compile_string_path(VALUE vparser, VALUE fname, VALUE src, int line);
VALUE rb_str_new_parser_string(rb_parser_string_t *str);
VALUE rb_str_new_mutable_parser_string(rb_parser_string_t *str);
+rb_parser_string_t *rb_parser_lex_get_str(struct parser_params *p, struct lex_pointer_string *ptr_str);
VALUE rb_node_str_string_val(const NODE *);
VALUE rb_node_sym_string_val(const NODE *);
@@ -40,16 +46,16 @@ VALUE rb_parser_end_seen_p(VALUE);
VALUE rb_parser_encoding(VALUE);
VALUE rb_parser_set_yydebug(VALUE, VALUE);
VALUE rb_parser_build_script_lines_from(rb_parser_ary_t *script_lines);
-void rb_parser_aset_script_lines_for(VALUE path, rb_parser_ary_t *script_lines);
void rb_parser_set_options(VALUE, int, int, int, int);
-void *rb_parser_load_file(VALUE parser, VALUE name);
+VALUE rb_parser_load_file(VALUE parser, VALUE name);
void rb_parser_set_script_lines(VALUE vparser);
void rb_parser_error_tolerant(VALUE vparser);
void rb_parser_keep_tokens(VALUE vparser);
-rb_ast_t *rb_parser_compile_string(VALUE, const char*, VALUE, int);
-rb_ast_t *rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE input, int line);
-rb_ast_t *rb_parser_compile_generic(VALUE vparser, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int line);
+VALUE rb_parser_compile_string(VALUE, const char*, VALUE, int);
+VALUE rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE input, int line);
+VALUE rb_parser_compile_generic(VALUE vparser, rb_parser_lex_gets_func *lex_gets, VALUE fname, VALUE input, int line);
+VALUE rb_parser_compile_array(VALUE vparser, VALUE fname, VALUE array, int start);
enum lex_state_bits {
EXPR_BEG_bit, /* ignore newline, +/- is a sign. */
@@ -90,4 +96,7 @@ enum lex_state_e {
EXPR_NONE = 0
};
+VALUE rb_ruby_ast_new(const NODE *const root);
+rb_ast_t *rb_ruby_ast_data_get(VALUE ast_value);
+
#endif /* INTERNAL_RUBY_PARSE_H */
diff --git a/io_buffer.c b/io_buffer.c
index 7715aa0d37..af884f1473 100644
--- a/io_buffer.c
+++ b/io_buffer.c
@@ -260,7 +260,7 @@ io_buffer_free(struct rb_io_buffer *buffer)
if (buffer->mapping) {
if (RB_IO_BUFFER_DEBUG) fprintf(stderr, "io_buffer_free:CloseHandle -> %p\n", buffer->mapping);
if (!CloseHandle(buffer->mapping)) {
- fprintf(stderr, "io_buffer_free:GetLastError -> %d\n", GetLastError());
+ fprintf(stderr, "io_buffer_free:GetLastError -> %lu\n", GetLastError());
}
buffer->mapping = NULL;
}
diff --git a/iseq.c b/iseq.c
index 15635332ff..aab58e3760 100644
--- a/iseq.c
+++ b/iseq.c
@@ -167,7 +167,7 @@ rb_iseq_free(const rb_iseq_t *iseq)
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
rb_rjit_free_iseq(iseq); /* Notify RJIT */
#if USE_YJIT
- rb_yjit_iseq_free(body->yjit_payload);
+ rb_yjit_iseq_free(iseq);
if (FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED)) {
RUBY_ASSERT(rb_yjit_live_iseq_count > 0);
rb_yjit_live_iseq_count--;
@@ -292,6 +292,10 @@ static bool
cc_is_active(const struct rb_callcache *cc, bool reference_updating)
{
if (cc) {
+ if (cc == rb_vm_empty_cc() || rb_vm_empty_cc_for_super()) {
+ return false;
+ }
+
if (reference_updating) {
cc = (const struct rb_callcache *)rb_gc_location((VALUE)cc);
}
@@ -373,7 +377,7 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating)
rb_rjit_iseq_update_references(body);
#endif
#if USE_YJIT
- rb_yjit_iseq_update_references(body->yjit_payload);
+ rb_yjit_iseq_update_references(iseq);
#endif
}
else {
@@ -835,32 +839,24 @@ make_compile_option_value(rb_compile_option_t *option)
}
rb_iseq_t *
-rb_iseq_new(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath,
+rb_iseq_new(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath,
const rb_iseq_t *parent, enum rb_iseq_type type)
{
- return rb_iseq_new_with_opt(ast, name, path, realpath, 0, parent,
+ return rb_iseq_new_with_opt(ast_value, name, path, realpath, 0, parent,
0, type, &COMPILE_OPTION_DEFAULT,
Qnil);
}
static int
-ast_line_count(const rb_ast_body_t *ast)
+ast_line_count(const VALUE ast_value)
{
- if (ast->script_lines == NULL) {
- // this occurs when failed to parse the source code with a syntax error
- return 0;
- }
- if (!FIXNUM_P((VALUE)ast->script_lines)) {
- return (int)ast->script_lines->len;
- }
- return FIX2INT((VALUE)ast->script_lines);
+ rb_ast_t *ast = rb_ruby_ast_data_get(ast_value);
+ return ast->body.line_count;
}
static VALUE
-iseq_setup_coverage(VALUE coverages, VALUE path, const rb_ast_body_t *ast, int line_offset)
+iseq_setup_coverage(VALUE coverages, VALUE path, int line_count)
{
- int line_count = line_offset + ast_line_count(ast);
-
if (line_count >= 0) {
int len = (rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES) ? 0 : line_count;
@@ -874,21 +870,21 @@ iseq_setup_coverage(VALUE coverages, VALUE path, const rb_ast_body_t *ast, int l
}
static inline void
-iseq_new_setup_coverage(VALUE path, const rb_ast_body_t *ast, int line_offset)
+iseq_new_setup_coverage(VALUE path, int line_count)
{
VALUE coverages = rb_get_coverages();
if (RTEST(coverages)) {
- iseq_setup_coverage(coverages, path, ast, line_offset);
+ iseq_setup_coverage(coverages, path, line_count);
}
}
rb_iseq_t *
-rb_iseq_new_top(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
+rb_iseq_new_top(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
{
- iseq_new_setup_coverage(path, ast, 0);
+ iseq_new_setup_coverage(path, ast_line_count(ast_value));
- return rb_iseq_new_with_opt(ast, name, path, realpath, 0, parent, 0,
+ return rb_iseq_new_with_opt(ast_value, name, path, realpath, 0, parent, 0,
ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT,
Qnil);
}
@@ -899,18 +895,18 @@ rb_iseq_new_top(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath
rb_iseq_t *
pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
{
- // iseq_new_setup_coverage(path, ast, 0);
+ iseq_new_setup_coverage(path, (int) (node->parser->newline_list.size - 1));
return pm_iseq_new_with_opt(node, name, path, realpath, 0, parent, 0,
ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT);
}
rb_iseq_t *
-rb_iseq_new_main(const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt)
+rb_iseq_new_main(const VALUE ast_value, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt)
{
- iseq_new_setup_coverage(path, ast, 0);
+ iseq_new_setup_coverage(path, ast_line_count(ast_value));
- return rb_iseq_new_with_opt(ast, rb_fstring_lit("<main>"),
+ return rb_iseq_new_with_opt(ast_value, rb_fstring_lit("<main>"),
path, realpath, 0,
parent, 0, ISEQ_TYPE_MAIN, opt ? &COMPILE_OPTION_DEFAULT : &COMPILE_OPTION_FALSE,
Qnil);
@@ -923,7 +919,7 @@ rb_iseq_new_main(const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_
rb_iseq_t *
pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt)
{
- // iseq_new_setup_coverage(path, ast, 0);
+ iseq_new_setup_coverage(path, (int) (node->parser->newline_list.size - 1));
return pm_iseq_new_with_opt(node, rb_fstring_lit("<main>"),
path, realpath, 0,
@@ -931,16 +927,16 @@ pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_ise
}
rb_iseq_t *
-rb_iseq_new_eval(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth)
+rb_iseq_new_eval(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth)
{
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, ast, first_lineno - 1);
+ iseq_setup_coverage(coverages, path, ast_line_count(ast_value) + first_lineno - 1);
}
}
- return rb_iseq_new_with_opt(ast, name, path, realpath, first_lineno,
+ return rb_iseq_new_with_opt(ast_value, name, path, realpath, first_lineno,
parent, isolated_depth, ISEQ_TYPE_EVAL, &COMPILE_OPTION_DEFAULT,
Qnil);
}
@@ -949,8 +945,15 @@ 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)
{
- return pm_iseq_new_with_opt(node, name, path, realpath, first_lineno,
- parent, isolated_depth, ISEQ_TYPE_EVAL, &COMPILE_OPTION_DEFAULT);
+ 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);
+ }
+ }
+
+ return pm_iseq_new_with_opt(node, name, path, realpath, first_lineno,
+ parent, isolated_depth, ISEQ_TYPE_EVAL, &COMPILE_OPTION_DEFAULT);
}
static inline rb_iseq_t *
@@ -968,27 +971,29 @@ iseq_translate(rb_iseq_t *iseq)
}
rb_iseq_t *
-rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath,
+rb_iseq_new_with_opt(const VALUE ast_value, 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,
VALUE script_lines)
{
- const NODE *node = ast ? ast->root : 0;
+ rb_ast_t *ast = rb_ruby_ast_data_get(ast_value);
+ rb_ast_body_t *body = ast ? &ast->body : NULL;
+ const NODE *node = body ? body->root : 0;
/* TODO: argument check */
rb_iseq_t *iseq = iseq_alloc();
rb_compile_option_t new_opt;
if (!option) option = &COMPILE_OPTION_DEFAULT;
- if (ast) {
+ if (body) {
new_opt = *option;
- option = set_compile_option_from_ast(&new_opt, ast);
+ option = set_compile_option_from_ast(&new_opt, body);
}
if (!NIL_P(script_lines)) {
// noop
}
- else if (ast && !FIXNUM_P((VALUE)ast->script_lines) && ast->script_lines) {
- script_lines = rb_parser_build_script_lines_from(ast->script_lines);
+ else if (body && body->script_lines) {
+ script_lines = rb_parser_build_script_lines_from(body->script_lines);
}
else if (parent) {
script_lines = ISEQ_BODY(parent)->variable.script_lines;
@@ -1210,9 +1215,10 @@ rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
#else
# define INITIALIZED /* volatile */
#endif
- rb_ast_t *(*parse)(VALUE vparser, VALUE fname, VALUE file, int start);
+ VALUE (*parse)(VALUE vparser, VALUE fname, VALUE file, int start);
int ln;
- rb_ast_t *INITIALIZED ast;
+ VALUE INITIALIZED ast_value;
+ rb_ast_t *ast;
VALUE name = rb_fstring_lit("<compiled>");
/* safe results first */
@@ -1228,20 +1234,22 @@ rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
}
{
const VALUE parser = rb_parser_new();
- const rb_iseq_t *outer_scope = rb_iseq_new(NULL, name, name, Qnil, 0, ISEQ_TYPE_TOP);
+ const rb_iseq_t *outer_scope = rb_iseq_new(Qnil, name, name, Qnil, 0, ISEQ_TYPE_TOP);
VALUE outer_scope_v = (VALUE)outer_scope;
rb_parser_set_context(parser, outer_scope, FALSE);
if (ruby_vm_keep_script_lines) rb_parser_set_script_lines(parser);
RB_GC_GUARD(outer_scope_v);
- ast = (*parse)(parser, file, src, ln);
+ ast_value = (*parse)(parser, file, src, ln);
}
- if (!ast->body.root) {
+ ast = rb_ruby_ast_data_get(ast_value);
+
+ if (!ast || !ast->body.root) {
rb_ast_dispose(ast);
rb_exc_raise(GET_EC()->errinfo);
}
else {
- iseq = rb_iseq_new_with_opt(&ast->body, name, file, realpath, ln,
+ iseq = rb_iseq_new_with_opt(ast_value, name, file, realpath, ln,
NULL, 0, ISEQ_TYPE_TOP, &option,
Qnil);
rb_ast_dispose(ast);
@@ -1266,6 +1274,20 @@ pm_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
pm_parse_result_t result = { 0 };
pm_options_line_set(&result.options, NUM2INT(line));
+ 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("pm_iseq_compile_with_option: invalid frozen_string_literal=%d", option.frozen_string_literal);
+ break;
+ }
+
VALUE error;
if (RB_TYPE_P(src, T_FILE)) {
VALUE filepath = rb_io_path(src);
@@ -1602,6 +1624,7 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
VALUE file, opt = Qnil;
VALUE parser, f, exc = Qnil, ret;
rb_ast_t *ast;
+ VALUE ast_value;
rb_compile_option_t option;
int i;
@@ -1620,7 +1643,8 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
parser = rb_parser_new();
rb_parser_set_context(parser, NULL, FALSE);
- ast = (rb_ast_t *)rb_parser_load_file(parser, file);
+ ast_value = rb_parser_load_file(parser, file);
+ ast = rb_ruby_ast_data_get(ast_value);
if (!ast->body.root) exc = GET_EC()->errinfo;
rb_io_close(f);
@@ -1631,7 +1655,7 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
make_compile_option(&option, opt);
- ret = iseqw_new(rb_iseq_new_with_opt(&ast->body, rb_fstring_lit("<main>"),
+ ret = iseqw_new(rb_iseq_new_with_opt(ast_value, rb_fstring_lit("<main>"),
file,
rb_realpath_internal(Qnil, file, 1),
1, NULL, 0, ISEQ_TYPE_TOP, &option,
diff --git a/lib/bundled_gems.rb b/lib/bundled_gems.rb
index a340463c98..c933ad0471 100644
--- a/lib/bundled_gems.rb
+++ b/lib/bundled_gems.rb
@@ -28,6 +28,7 @@ module Gem::BUNDLED_GEMS
"syslog" => "3.4.0",
"ostruct" => "3.5.0",
"pstore" => "3.5.0",
+ "rdoc" => "3.5.0",
}.freeze
EXACT = {
@@ -45,6 +46,7 @@ module Gem::BUNDLED_GEMS
"syslog" => true,
"ostruct" => true,
"pstore" => true,
+ "rdoc" => true,
}.freeze
PREFIXED = {
@@ -101,8 +103,11 @@ module Gem::BUNDLED_GEMS
def self.warning?(name, specs: nil)
# name can be a feature name or a file path with String or Pathname
feature = File.path(name)
- # bootsnap expand `require "csv"` to `require "#{LIBDIR}/csv.rb"`
- name = feature.delete_prefix(LIBDIR).chomp(".rb").tr("/", "-")
+ # bootsnap expands `require "csv"` to `require "#{LIBDIR}/csv.rb"`,
+ # and `require "syslog"` to `require "#{ARCHDIR}/syslog.so"`.
+ name = feature.delete_prefix(ARCHDIR)
+ name.delete_prefix!(LIBDIR)
+ name.tr!("/", "-")
name.sub!(LIBEXT, "")
return if specs.include?(name)
_t, path = $:.resolve_feature_path(feature)
diff --git a/lib/bundler.rb b/lib/bundler.rb
index 59a1107bb7..5033109db6 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -40,6 +40,7 @@ module Bundler
SUDO_MUTEX = Thread::Mutex.new
autoload :Checksum, File.expand_path("bundler/checksum", __dir__)
+ autoload :CLI, File.expand_path("bundler/cli", __dir__)
autoload :CIDetector, File.expand_path("bundler/ci_detector", __dir__)
autoload :Definition, File.expand_path("bundler/definition", __dir__)
autoload :Dependency, File.expand_path("bundler/dependency", __dir__)
@@ -165,6 +166,25 @@ module Bundler
end
end
+ # Automatically install dependencies if Bundler.settings[:auto_install] exists.
+ # This is set through config cmd `bundle config set --global auto_install 1`.
+ #
+ # Note that this method `nil`s out the global Definition object, so it
+ # should be called first, before you instantiate anything like an
+ # `Installer` that'll keep a reference to the old one instead.
+ def auto_install
+ return unless settings[:auto_install]
+
+ begin
+ definition.specs
+ rescue GemNotFound, GitError
+ ui.info "Automatically installing missing gems."
+ reset!
+ CLI::Install.new({}).run
+ reset!
+ end
+ end
+
# Setups Bundler environment (see Bundler.setup) if it is not already set,
# and loads all gems from groups specified. Unlike ::setup, can be called
# multiple times with different groups (if they were allowed by setup).
@@ -184,6 +204,7 @@ module Bundler
# Bundler.require(:test) # requires second_gem
#
def require(*groups)
+ load_plugins
setup(*groups).require(*groups)
end
@@ -560,6 +581,23 @@ module Bundler
@feature_flag ||= FeatureFlag.new(VERSION)
end
+ def load_plugins(definition = Bundler.definition)
+ return if defined?(@load_plugins_ran)
+
+ Bundler.rubygems.load_plugins
+
+ requested_path_gems = definition.requested_specs.select {|s| s.source.is_a?(Source::Path) }
+ path_plugin_files = requested_path_gems.map do |spec|
+ Bundler.rubygems.spec_matches_for_glob(spec, "rubygems_plugin#{Bundler.rubygems.suffix_pattern}")
+ rescue TypeError
+ error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
+ raise Gem::InvalidSpecificationException, error_message
+ end.flatten
+ Bundler.rubygems.load_plugin_files(path_plugin_files)
+ Bundler.rubygems.load_env_plugins
+ @load_plugins_ran = true
+ end
+
def reset!
reset_paths!
Plugin.reset!
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb
index 8db725bbde..40f19c7fed 100644
--- a/lib/bundler/cli.rb
+++ b/lib/bundler/cli.rb
@@ -5,6 +5,7 @@ require_relative "vendored_thor"
module Bundler
class CLI < Thor
require_relative "cli/common"
+ require_relative "cli/install"
package_name "Bundler"
@@ -69,7 +70,7 @@ module Bundler
Bundler.settings.set_command_option_if_given :retry, options[:retry]
current_cmd = args.last[:current_command].name
- auto_install if AUTO_INSTALL_CMDS.include?(current_cmd)
+ Bundler.auto_install if AUTO_INSTALL_CMDS.include?(current_cmd)
rescue UnknownArgumentError => e
raise InvalidOption, e.message
ensure
@@ -114,6 +115,8 @@ module Bundler
class_option "verbose", type: :boolean, desc: "Enable verbose output mode", aliases: "-V"
def help(cli = nil)
+ cli = self.class.all_aliases[cli] if self.class.all_aliases[cli]
+
case cli
when "gemfile" then command = "gemfile"
when nil then command = "bundle"
@@ -683,7 +686,6 @@ module Bundler
exec_used = args.index {|a| exec_commands.include? a }
command = args.find {|a| bundler_commands.include? a }
- command = all_aliases[command] if all_aliases[command]
if exec_used && help_used
if exec_used + help_used == 1
@@ -736,26 +738,6 @@ module Bundler
private
- # Automatically invoke `bundle install` and resume if
- # Bundler.settings[:auto_install] exists. This is set through config cmd
- # `bundle config set --global auto_install 1`.
- #
- # Note that this method `nil`s out the global Definition object, so it
- # should be called first, before you instantiate anything like an
- # `Installer` that'll keep a reference to the old one instead.
- def auto_install
- return unless Bundler.settings[:auto_install]
-
- begin
- Bundler.definition.specs
- rescue GemNotFound, GitError
- Bundler.ui.info "Automatically installing missing gems."
- Bundler.reset!
- invoke :install, []
- Bundler.reset!
- end
- end
-
def current_command
_, _, config = @_initializer
config[:current_command]
diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb
index 6c102d537d..a233d5d2e5 100644
--- a/lib/bundler/cli/install.rb
+++ b/lib/bundler/cli/install.rb
@@ -14,7 +14,7 @@ module Bundler
Bundler.self_manager.install_locked_bundler_and_restart_with_it_if_needed
- Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Bundler::FREEBSD
+ 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]
diff --git a/lib/bundler/constants.rb b/lib/bundler/constants.rb
index de9698b577..9564771e78 100644
--- a/lib/bundler/constants.rb
+++ b/lib/bundler/constants.rb
@@ -1,7 +1,14 @@
# frozen_string_literal: true
+require "rbconfig"
+
module Bundler
WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/
+ deprecate_constant :WINDOWS
+
FREEBSD = RbConfig::CONFIG["host_os"].to_s.include?("bsd")
- NULL = File::NULL
+ deprecate_constant :FREEBSD
+
+ NULL = File::NULL
+ deprecate_constant :NULL
end
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index c8faf77b3b..22070b6b17 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -92,11 +92,12 @@ module Bundler
@platforms = @locked_platforms.dup
@locked_bundler_version = @locked_gems.bundler_version
@locked_ruby_version = @locked_gems.ruby_version
+ @originally_locked_deps = @locked_gems.dependencies
@originally_locked_specs = SpecSet.new(@locked_gems.specs)
@locked_checksums = @locked_gems.checksums
if unlock != true
- @locked_deps = @locked_gems.dependencies
+ @locked_deps = @originally_locked_deps
@locked_specs = @originally_locked_specs
@locked_sources = @locked_gems.sources
else
@@ -111,6 +112,7 @@ module Bundler
@locked_gems = nil
@locked_deps = {}
@locked_specs = SpecSet.new([])
+ @originally_locked_deps = {}
@originally_locked_specs = @locked_specs
@locked_sources = []
@locked_platforms = []
@@ -130,7 +132,7 @@ module Bundler
@sources.merged_gem_lockfile_sections!(locked_gem_sources.first)
end
- @unlock[:sources] ||= []
+ @sources_to_unlock = @unlock.delete(:sources) || []
@unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object
@ruby_version.diff(locked_ruby_version_object)
end
@@ -142,11 +144,13 @@ module Bundler
@path_changes = converge_paths
@source_changes = converge_sources
+ @explicit_unlocks = @unlock.delete(:gems) || []
+
if @unlock[:conservative]
- @unlock[:gems] ||= @dependencies.map(&:name)
+ @gems_to_unlock = @explicit_unlocks.any? ? @explicit_unlocks : @dependencies.map(&:name)
else
- eager_unlock = (@unlock[:gems] || []).map {|name| Dependency.new(name, ">= 0") }
- @unlock[:gems] = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq
+ eager_unlock = @explicit_unlocks.map {|name| Dependency.new(name, ">= 0") }
+ @gems_to_unlock = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq
end
@dependency_changes = converge_dependencies
@@ -225,7 +229,6 @@ module Bundler
@resolver = nil
@resolution_packages = nil
@specs = nil
- @gem_version_promoter = nil
Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})"
true
@@ -566,8 +569,10 @@ module Bundler
@resolution_packages ||= begin
last_resolve = converge_locked_specs
remove_invalid_platforms!(current_dependencies)
- packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @unlock[:gems], prerelease: gem_version_promoter.pre?)
- additional_base_requirements_for_resolve(packages, last_resolve)
+ packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @gems_to_unlock, prerelease: gem_version_promoter.pre?)
+ packages = additional_base_requirements_to_prevent_downgrades(packages, last_resolve)
+ packages = additional_base_requirements_to_force_updates(packages)
+ packages
end
end
@@ -671,14 +676,18 @@ module Bundler
def change_reason
if unlocking?
- unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v|
- if v == true
- k.to_s
- else
- v = Array(v)
- "#{k}: (#{v.join(", ")})"
- end
- end.join(", ")
+ unlock_targets = if @gems_to_unlock.any?
+ ["gems", @gems_to_unlock]
+ elsif @sources_to_unlock.any?
+ ["sources", @sources_to_unlock]
+ end
+
+ unlock_reason = if unlock_targets
+ "#{unlock_targets.first}: (#{unlock_targets.last.join(", ")})"
+ else
+ @unlock[:ruby] ? "ruby" : ""
+ end
+
return "bundler is unlocking #{unlock_reason}"
end
[
@@ -733,7 +742,7 @@ module Bundler
spec = @dependencies.find {|s| s.name == k }
source = spec&.source
if source&.respond_to?(:local_override!)
- source.unlock! if @unlock[:gems].include?(spec.name)
+ source.unlock! if @gems_to_unlock.include?(spec.name)
locals << [source, source.local_override!(v)]
end
end
@@ -741,7 +750,7 @@ module Bundler
sources_with_changes = locals.select do |source, changed|
changed || specs_changed?(source)
end.map(&:first)
- !sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty?
+ !sources_with_changes.each {|source| @sources_to_unlock << source.name }.empty?
end
def check_lockfile
@@ -818,7 +827,7 @@ module Bundler
# gem), unlock it. For git sources, this means to unlock the revision, which
# will cause the `ref` used to be the most recent for the branch (or master) if
# an explicit `ref` is not used.
- if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
+ if source.respond_to?(:unlock!) && @sources_to_unlock.include?(source.name)
source.unlock!
changes = true
end
@@ -835,9 +844,7 @@ module Bundler
dep.source = sources.get(dep.source)
end
- next if unlocking?
-
- unless locked_dep = @locked_deps[dep.name]
+ unless locked_dep = @originally_locked_deps[dep.name]
changes = true
next
end
@@ -864,7 +871,7 @@ module Bundler
def converge_locked_specs
converged = converge_specs(@locked_specs)
- resolve = SpecSet.new(converged.reject {|s| @unlock[:gems].include?(s.name) })
+ resolve = SpecSet.new(converged.reject {|s| @gems_to_unlock.include?(s.name) })
diff = nil
@@ -897,7 +904,7 @@ module Bundler
@specs_that_changed_sources << s if gemfile_source != lockfile_source
deps << dep if !dep.source || lockfile_source.include?(dep.source)
- @unlock[:gems] << name if lockfile_source.include?(dep.source) && lockfile_source != gemfile_source
+ @gems_to_unlock << name if lockfile_source.include?(dep.source) && lockfile_source != gemfile_source
# Replace the locked dependency's source with the equivalent source from the Gemfile
s.source = gemfile_source
@@ -906,7 +913,7 @@ module Bundler
s.source = default_source unless sources.get(lockfile_source)
end
- next if @unlock[:sources].include?(s.source.name)
+ next if @sources_to_unlock.include?(s.source.name)
# Path sources have special logic
if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
@@ -928,12 +935,12 @@ module Bundler
else
# If the spec is no longer in the path source, unlock it. This
# commonly happens if the version changed in the gemspec
- @unlock[:gems] << name
+ @gems_to_unlock << name
end
end
if dep.nil? && requested_dependencies.find {|d| name == d.name }
- @unlock[:gems] << s.name
+ @gems_to_unlock << s.name
else
converged << s
end
@@ -1010,7 +1017,7 @@ module Bundler
current == proposed
end
- def additional_base_requirements_for_resolve(resolution_packages, last_resolve)
+ def additional_base_requirements_to_prevent_downgrades(resolution_packages, last_resolve)
return resolution_packages unless @locked_gems && !sources.expired_sources?(@locked_gems.sources)
converge_specs(@originally_locked_specs - last_resolve).each do |locked_spec|
next if locked_spec.source.is_a?(Source::Path)
@@ -1019,6 +1026,28 @@ module Bundler
resolution_packages
end
+ def additional_base_requirements_to_force_updates(resolution_packages)
+ return resolution_packages if @explicit_unlocks.empty?
+ full_update = dup_for_full_unlock.resolve
+ @explicit_unlocks.each do |name|
+ version = full_update[name].first&.version
+ resolution_packages.base_requirements[name] = Gem::Requirement.new("= #{version}") if version
+ end
+ resolution_packages
+ end
+
+ def dup_for_full_unlock
+ unlocked_definition = self.class.new(@lockfile, @dependencies, @sources, true, @ruby_version, @optional_groups, @gemfiles)
+ unlocked_definition.resolution_mode = { "local" => !@remote }
+ unlocked_definition.setup_sources_for_resolve
+ unlocked_definition.gem_version_promoter.tap do |gvp|
+ gvp.level = gem_version_promoter.level
+ gvp.strict = gem_version_promoter.strict
+ gvp.pre = gem_version_promoter.pre
+ end
+ unlocked_definition
+ end
+
def remove_invalid_platforms!(dependencies)
return if Bundler.frozen_bundle?
diff --git a/lib/bundler/environment_preserver.rb b/lib/bundler/environment_preserver.rb
index c4c1b53fa4..444ab6fd37 100644
--- a/lib/bundler/environment_preserver.rb
+++ b/lib/bundler/environment_preserver.rb
@@ -19,14 +19,7 @@ module Bundler
BUNDLER_PREFIX = "BUNDLER_ORIG_"
def self.from_env
- new(env_to_hash(ENV), BUNDLER_KEYS)
- end
-
- def self.env_to_hash(env)
- to_hash = env.to_hash
- return to_hash unless Gem.win_platform?
-
- to_hash.each_with_object({}) {|(k,v), a| a[k.upcase] = v }
+ new(ENV.to_hash, BUNDLER_KEYS)
end
# @param env [Hash]
@@ -39,18 +32,7 @@ module Bundler
# Replaces `ENV` with the bundler environment variables backed up
def replace_with_backup
- unless Gem.win_platform?
- ENV.replace(backup)
- return
- end
-
- # Fallback logic for Windows below to workaround
- # https://bugs.ruby-lang.org/issues/16798. Can be dropped once all
- # supported rubies include the fix for that.
-
- ENV.clear
-
- backup.each {|k, v| ENV[k] = v }
+ ENV.replace(backup)
end
# @return [Hash]
diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb
index b6a11cc721..c29b1bfed8 100644
--- a/lib/bundler/errors.rb
+++ b/lib/bundler/errors.rb
@@ -230,4 +230,18 @@ module Bundler
status_code(38)
end
+
+ class CorruptBundlerInstallError < BundlerError
+ def initialize(loaded_spec)
+ @loaded_spec = loaded_spec
+ end
+
+ def message
+ "The running version of Bundler (#{Bundler::VERSION}) does not match the version of the specification installed for it (#{@loaded_spec.version}). " \
+ "This can be caused by reinstalling Ruby without removing previous installation, leaving around an upgraded default version of Bundler. " \
+ "Reinstalling Ruby from scratch should fix the problem."
+ end
+
+ status_code(39)
+ end
end
diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb
index 018324f840..72e5602cc3 100644
--- a/lib/bundler/installer.rb
+++ b/lib/bundler/installer.rb
@@ -81,7 +81,7 @@ module Bundler
if resolve_if_needed(options)
ensure_specs_are_compatible!
- load_plugins
+ Bundler.load_plugins(@definition)
options.delete(:jobs)
else
options[:jobs] = 1 # to avoid the overhead of Bundler::Worker
@@ -213,20 +213,6 @@ module Bundler
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) }
- path_plugin_files = requested_path_gems.map do |spec|
- Bundler.rubygems.spec_matches_for_glob(spec, "rubygems_plugin#{Bundler.rubygems.suffix_pattern}")
- rescue TypeError
- error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
- raise Gem::InvalidSpecificationException, error_message
- end.flatten
- Gem.load_plugin_files(path_plugin_files)
- Gem.load_env_plugins
- end
-
def ensure_specs_are_compatible!
@definition.specs.each do |spec|
unless spec.matches_current_ruby?
diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1
index a6cbc88f34..56a3b6f85c 100644
--- a/lib/bundler/man/bundle-add.1
+++ b/lib/bundler/man/bundle-add.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-ADD" "1" "March 2024" ""
+.TH "BUNDLE\-ADD" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1
index 2b35bc956a..4ec301951f 100644
--- a/lib/bundler/man/bundle-binstubs.1
+++ b/lib/bundler/man/bundle-binstubs.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-BINSTUBS" "1" "March 2024" ""
+.TH "BUNDLE\-BINSTUBS" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-binstubs\fR \- Install the binstubs of the listed gems
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1
index 3b86b995a6..e2da1269e6 100644
--- a/lib/bundler/man/bundle-cache.1
+++ b/lib/bundler/man/bundle-cache.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CACHE" "1" "March 2024" ""
+.TH "BUNDLE\-CACHE" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1
index 7f18e26537..dee1af1326 100644
--- a/lib/bundler/man/bundle-check.1
+++ b/lib/bundler/man/bundle-check.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CHECK" "1" "March 2024" ""
+.TH "BUNDLE\-CHECK" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems
.SH "SYNOPSIS"
@@ -9,6 +9,8 @@
\fBcheck\fR searches the local machine for each of the gems requested in the Gemfile\. If all gems are found, Bundler prints a success message and exits with a status of 0\.
.P
If not, the first missing gem is listed and Bundler exits status 1\.
+.P
+If the lockfile needs to be updated then it will be resolved using the gems installed on the local machine, if they satisfy the requirements\.
.SH "OPTIONS"
.TP
\fB\-\-dry\-run\fR
diff --git a/lib/bundler/man/bundle-check.1.ronn b/lib/bundler/man/bundle-check.1.ronn
index f2846b8ff2..eb3ff1daf9 100644
--- a/lib/bundler/man/bundle-check.1.ronn
+++ b/lib/bundler/man/bundle-check.1.ronn
@@ -15,6 +15,9 @@ a status of 0.
If not, the first missing gem is listed and Bundler exits status 1.
+If the lockfile needs to be updated then it will be resolved using the gems
+installed on the local machine, if they satisfy the requirements.
+
## OPTIONS
* `--dry-run`:
diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1
index 0180eb38a2..7c7f9b5c77 100644
--- a/lib/bundler/man/bundle-clean.1
+++ b/lib/bundler/man/bundle-clean.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CLEAN" "1" "March 2024" ""
+.TH "BUNDLE\-CLEAN" "1" "May 2024" ""
.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 b768f1e3d2..a207dbbcaa 100644
--- a/lib/bundler/man/bundle-config.1
+++ b/lib/bundler/man/bundle-config.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CONFIG" "1" "March 2024" ""
+.TH "BUNDLE\-CONFIG" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-config\fR \- Set bundler configuration options
.SH "SYNOPSIS"
@@ -95,8 +95,6 @@ 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_deployment_source_credential_changes\fR (\fBBUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES\fR): When in deployment mode, allow changing the credentials to a gem's source\. Ex: \fBhttps://some\.host\.com/gems/path/\fR \-> \fBhttps://user_name:password@some\.host\.com/gems/path\fR
-.IP "\(bu" 4
\fBallow_offline_install\fR (\fBBUNDLE_ALLOW_OFFLINE_INSTALL\fR): Allow Bundler to use cached data when installing without network access\.
.IP "\(bu" 4
\fBauto_clean_without_path\fR (\fBBUNDLE_AUTO_CLEAN_WITHOUT_PATH\fR): Automatically run \fBbundle clean\fR after installing when an explicit \fBpath\fR has not been set and Bundler is not installing into the system gems\.
diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn
index 587d31dbad..7e5f458fb2 100644
--- a/lib/bundler/man/bundle-config.1.ronn
+++ b/lib/bundler/man/bundle-config.1.ronn
@@ -137,9 +137,6 @@ the environment variable `BUNDLE_LOCAL__RACK`.
The following is a list of all configuration keys and their purpose. You can
learn more about their operation in [bundle install(1)](bundle-install.1.html).
-* `allow_deployment_source_credential_changes` (`BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES`):
- When in deployment mode, allow changing the credentials to a gem's source.
- Ex: `https://some.host.com/gems/path/` -> `https://user_name:password@some.host.com/gems/path`
* `allow_offline_install` (`BUNDLE_ALLOW_OFFLINE_INSTALL`):
Allow Bundler to use cached data when installing without network access.
* `auto_clean_without_path` (`BUNDLE_AUTO_CLEAN_WITHOUT_PATH`):
diff --git a/lib/bundler/man/bundle-console.1 b/lib/bundler/man/bundle-console.1
index 1368a50eb1..dca18ec43d 100644
--- a/lib/bundler/man/bundle-console.1
+++ b/lib/bundler/man/bundle-console.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CONSOLE" "1" "March 2024" ""
+.TH "BUNDLE\-CONSOLE" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-console\fR \- Deprecated way to 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 80eaf2a888..6489cc07f7 100644
--- a/lib/bundler/man/bundle-doctor.1
+++ b/lib/bundler/man/bundle-doctor.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-DOCTOR" "1" "March 2024" ""
+.TH "BUNDLE\-DOCTOR" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-doctor\fR \- Checks the bundle for common problems
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1
index 191863c045..1548d29670 100644
--- a/lib/bundler/man/bundle-exec.1
+++ b/lib/bundler/man/bundle-exec.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-EXEC" "1" "March 2024" ""
+.TH "BUNDLE\-EXEC" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-exec\fR \- Execute a command in the context of the bundle
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1
index 464d8d1126..5df7b0ef2f 100644
--- a/lib/bundler/man/bundle-gem.1
+++ b/lib/bundler/man/bundle-gem.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-GEM" "1" "March 2024" ""
+.TH "BUNDLE\-GEM" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-help.1 b/lib/bundler/man/bundle-help.1
index 3604ad6127..a3e7c7770d 100644
--- a/lib/bundler/man/bundle-help.1
+++ b/lib/bundler/man/bundle-help.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-HELP" "1" "March 2024" ""
+.TH "BUNDLE\-HELP" "1" "May 2024" ""
.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 647f5987be..a3d7ff0988 100644
--- a/lib/bundler/man/bundle-info.1
+++ b/lib/bundler/man/bundle-info.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-INFO" "1" "March 2024" ""
+.TH "BUNDLE\-INFO" "1" "May 2024" ""
.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 2c41a3c7de..a0edaaa18f 100644
--- a/lib/bundler/man/bundle-init.1
+++ b/lib/bundler/man/bundle-init.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-INIT" "1" "March 2024" ""
+.TH "BUNDLE\-INIT" "1" "May 2024" ""
.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
index c7269db34d..7a1038206e 100644
--- a/lib/bundler/man/bundle-inject.1
+++ b/lib/bundler/man/bundle-inject.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-INJECT" "1" "March 2024" ""
+.TH "BUNDLE\-INJECT" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1
index 3fa1a467e2..cc46a03b7f 100644
--- a/lib/bundler/man/bundle-install.1
+++ b/lib/bundler/man/bundle-install.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-INSTALL" "1" "March 2024" ""
+.TH "BUNDLE\-INSTALL" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-install\fR \- Install the dependencies specified in your Gemfile
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1
index f91fd95739..21723608cc 100644
--- a/lib/bundler/man/bundle-list.1
+++ b/lib/bundler/man/bundle-list.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-LIST" "1" "March 2024" ""
+.TH "BUNDLE\-LIST" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-list\fR \- List all the gems in the bundle
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1
index f992f5ee5f..8b81b7732f 100644
--- a/lib/bundler/man/bundle-lock.1
+++ b/lib/bundler/man/bundle-lock.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-LOCK" "1" "March 2024" ""
+.TH "BUNDLE\-LOCK" "1" "May 2024" ""
.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 53d3541555..41a8804a09 100644
--- a/lib/bundler/man/bundle-open.1
+++ b/lib/bundler/man/bundle-open.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-OPEN" "1" "March 2024" ""
+.TH "BUNDLE\-OPEN" "1" "May 2024" ""
.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 f79eff5ae9..838fce45cd 100644
--- a/lib/bundler/man/bundle-outdated.1
+++ b/lib/bundler/man/bundle-outdated.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-OUTDATED" "1" "March 2024" ""
+.TH "BUNDLE\-OUTDATED" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-outdated\fR \- List installed gems with newer versions available
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1
index d2133ec4d3..0dbce7a7a4 100644
--- a/lib/bundler/man/bundle-platform.1
+++ b/lib/bundler/man/bundle-platform.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-PLATFORM" "1" "March 2024" ""
+.TH "BUNDLE\-PLATFORM" "1" "May 2024" ""
.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 cbdfac11b6..1290abb3ba 100644
--- a/lib/bundler/man/bundle-plugin.1
+++ b/lib/bundler/man/bundle-plugin.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-PLUGIN" "1" "March 2024" ""
+.TH "BUNDLE\-PLUGIN" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-plugin\fR \- Manage Bundler plugins
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1
index faa04d7676..bf4a7cd323 100644
--- a/lib/bundler/man/bundle-pristine.1
+++ b/lib/bundler/man/bundle-pristine.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-PRISTINE" "1" "March 2024" ""
+.TH "BUNDLE\-PRISTINE" "1" "May 2024" ""
.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 3f8cbbd9b6..c3c96b416d 100644
--- a/lib/bundler/man/bundle-remove.1
+++ b/lib/bundler/man/bundle-remove.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-REMOVE" "1" "March 2024" ""
+.TH "BUNDLE\-REMOVE" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-remove\fR \- Removes gems from the Gemfile
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1
index bc72c6e3b6..c054875efd 100644
--- a/lib/bundler/man/bundle-show.1
+++ b/lib/bundler/man/bundle-show.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-SHOW" "1" "March 2024" ""
+.TH "BUNDLE\-SHOW" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1
index d1284c2e72..acd80ec75c 100644
--- a/lib/bundler/man/bundle-update.1
+++ b/lib/bundler/man/bundle-update.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-UPDATE" "1" "March 2024" ""
+.TH "BUNDLE\-UPDATE" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-update\fR \- Update your gems to the latest available versions
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-version.1 b/lib/bundler/man/bundle-version.1
index 05905e1347..44eaf92224 100644
--- a/lib/bundler/man/bundle-version.1
+++ b/lib/bundler/man/bundle-version.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-VERSION" "1" "March 2024" ""
+.TH "BUNDLE\-VERSION" "1" "May 2024" ""
.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
index 681563cd4c..77b902214c 100644
--- a/lib/bundler/man/bundle-viz.1
+++ b/lib/bundler/man/bundle-viz.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-VIZ" "1" "March 2024" ""
+.TH "BUNDLE\-VIZ" "1" "May 2024" ""
.SH "NAME"
\fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1
index 1d2c780060..199d1ce9fd 100644
--- a/lib/bundler/man/bundle.1
+++ b/lib/bundler/man/bundle.1
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE" "1" "March 2024" ""
+.TH "BUNDLE" "1" "May 2024" ""
.SH "NAME"
\fBbundle\fR \- Ruby Dependency Management
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5
index 39503f22a6..fa9e31f615 100644
--- a/lib/bundler/man/gemfile.5
+++ b/lib/bundler/man/gemfile.5
@@ -1,6 +1,6 @@
.\" generated with nRonn/v0.11.1
.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "GEMFILE" "5" "March 2024" ""
+.TH "GEMFILE" "5" "May 2024" ""
.SH "NAME"
\fBGemfile\fR \- A format for describing gem dependencies for Ruby programs
.SH "SYNOPSIS"
diff --git a/lib/bundler/plugin/events.rb b/lib/bundler/plugin/events.rb
index bc037d1af5..29c05098ae 100644
--- a/lib/bundler/plugin/events.rb
+++ b/lib/bundler/plugin/events.rb
@@ -56,6 +56,30 @@ module Bundler
# 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 each individual gem is required
+ # Includes a Bundler::Dependency.
+ # GEM_BEFORE_REQUIRE = "before-require"
+ define :GEM_BEFORE_REQUIRE, "before-require"
+
+ # @!parse
+ # A hook called after each individual gem is required
+ # Includes a Bundler::Dependency.
+ # GEM_AFTER_REQUIRE = "after-require"
+ 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"
end
end
end
diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb
index e0582beba2..18180a81a1 100644
--- a/lib/bundler/rubygems_ext.rb
+++ b/lib/bundler/rubygems_ext.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: true
-require "pathname"
-
require "rubygems" unless defined?(Gem)
-require "rubygems/specification"
-
# We can't let `Gem::Source` be autoloaded in the `Gem::Specification#source`
# redefinition below, so we need to load it upfront. The reason is that if
# Bundler monkeypatches are loaded before RubyGems activates an executable (for
@@ -17,10 +13,6 @@ require "rubygems/specification"
# `Gem::Source` from the redefined `Gem::Specification#source`.
require "rubygems/source"
-require_relative "match_metadata"
-require_relative "force_platform"
-require_relative "match_platform"
-
# Cherry-pick fixes to `Gem.ruby_version` to be useful for modern Bundler
# versions and ignore patchlevels
# (https://github.com/rubygems/rubygems/pull/5472,
@@ -31,7 +23,19 @@ unless Gem.ruby_version.to_s == RUBY_VERSION || RUBY_PATCHLEVEL == -1
end
module Gem
+ # Can be removed once RubyGems 3.5.11 support is dropped
+ unless Gem.respond_to?(:freebsd_platform?)
+ def self.freebsd_platform?
+ RbConfig::CONFIG["host_os"].to_s.include?("bsd")
+ end
+ end
+
+ require "rubygems/specification"
+
class Specification
+ require_relative "match_metadata"
+ require_relative "match_platform"
+
include ::Bundler::MatchMetadata
include ::Bundler::MatchPlatform
@@ -48,7 +52,7 @@ module Gem
def full_gem_path
if source.respond_to?(:root)
- Pathname.new(loaded_from).dirname.expand_path(source.root).to_s
+ File.expand_path(File.dirname(loaded_from), source.root)
else
rg_full_gem_path
end
@@ -146,7 +150,23 @@ module Gem
end
end
+ module BetterPermissionError
+ def data
+ super
+ rescue Errno::EACCES
+ raise Bundler::PermissionError.new(loaded_from, :read)
+ end
+ end
+
+ require "rubygems/stub_specification"
+
+ class StubSpecification
+ prepend BetterPermissionError
+ end
+
class Dependency
+ require_relative "force_platform"
+
include ::Bundler::ForcePlatform
attr_accessor :source, :groups
diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb
index da555681f9..494030eab2 100644
--- a/lib/bundler/rubygems_integration.rb
+++ b/lib/bundler/rubygems_integration.rb
@@ -156,6 +156,18 @@ module Bundler
loaded_gem_paths.flatten
end
+ def load_plugins
+ Gem.load_plugins
+ end
+
+ def load_plugin_files(plugin_files)
+ Gem.load_plugin_files(plugin_files)
+ end
+
+ def load_env_plugins
+ Gem.load_env_plugins
+ end
+
def ui=(obj)
Gem::DefaultUserInteraction.ui = obj
end
diff --git a/lib/bundler/runtime.rb b/lib/bundler/runtime.rb
index ec772cfe7b..54aa30ce0b 100644
--- a/lib/bundler/runtime.rb
+++ b/lib/bundler/runtime.rb
@@ -41,12 +41,17 @@ module Bundler
groups.map!(&:to_sym)
groups = [:default] if groups.empty?
- @definition.dependencies.each do |dep|
- # Skip the dependency if it is not in any of the requested groups, or
- # not for the current platform, or doesn't match the gem constraints.
- next unless (dep.groups & groups).any? && dep.should_include?
+ dependencies = @definition.dependencies.select do |dep|
+ # Select the dependency if it is in any of the requested groups, and
+ # for the current platform, and matches the gem constraints.
+ (dep.groups & groups).any? && dep.should_include?
+ end
+
+ Plugin.hook(Plugin::Events::GEM_BEFORE_REQUIRE_ALL, dependencies)
+ dependencies.each do |dep|
required_file = nil
+ Plugin.hook(Plugin::Events::GEM_BEFORE_REQUIRE, dep)
begin
# Loop through all the specified autorequires for the
@@ -76,7 +81,13 @@ module Bundler
end
end
end
+
+ Plugin.hook(Plugin::Events::GEM_AFTER_REQUIRE, dep)
end
+
+ Plugin.hook(Plugin::Events::GEM_AFTER_REQUIRE_ALL, dependencies)
+
+ dependencies
end
def self.definition_method(meth)
diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb
index 379abfb24a..abbaec9783 100644
--- a/lib/bundler/settings.rb
+++ b/lib/bundler/settings.rb
@@ -7,7 +7,6 @@ module Bundler
autoload :Validator, File.expand_path("settings/validator", __dir__)
BOOL_KEYS = %w[
- allow_deployment_source_credential_changes
allow_offline_install
auto_clean_without_path
auto_install
diff --git a/lib/bundler/setup.rb b/lib/bundler/setup.rb
index 7131d15055..6010d66742 100644
--- a/lib/bundler/setup.rb
+++ b/lib/bundler/setup.rb
@@ -5,6 +5,9 @@ require_relative "shared_helpers"
if Bundler::SharedHelpers.in_bundle?
require_relative "../bundler"
+ # try to auto_install first before we get to the `Bundler.ui.silence`, so user knows what is happening
+ Bundler.auto_install
+
if STDOUT.tty? || ENV["BUNDLER_FORCE_TTY"]
begin
Bundler.ui.silence { Bundler.setup }
diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb
index 78760e6fa4..28f0cdff19 100644
--- a/lib/bundler/shared_helpers.rb
+++ b/lib/bundler/shared_helpers.rb
@@ -1,15 +1,17 @@
# frozen_string_literal: true
-require "pathname"
-require "rbconfig"
-
require_relative "version"
-require_relative "constants"
require_relative "rubygems_integration"
require_relative "current_ruby"
module Bundler
+ autoload :WINDOWS, File.expand_path("constants", __dir__)
+ autoload :FREEBSD, File.expand_path("constants", __dir__)
+ autoload :NULL, File.expand_path("constants", __dir__)
+
module SharedHelpers
+ autoload :Pathname, "pathname"
+
def root
gemfile = find_gemfile
raise GemfileNotFound, "Could not locate Gemfile" unless gemfile
diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb
index 4d27761365..6b05e17727 100644
--- a/lib/bundler/source/metadata.rb
+++ b/lib/bundler/source/metadata.rb
@@ -11,6 +11,8 @@ module Bundler
end
if local_spec = Gem.loaded_specs["bundler"]
+ raise CorruptBundlerInstallError.new(local_spec) if local_spec.version.to_s != Bundler::VERSION
+
idx << local_spec
else
idx << Gem::Specification.new do |s|
diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb
index 04cfc0a850..2e76becb84 100644
--- a/lib/bundler/source/rubygems.rb
+++ b/lib/bundler/source/rubygems.rb
@@ -10,7 +10,7 @@ module Bundler
# Ask for X gems per API request
API_REQUEST_SIZE = 50
- attr_reader :remotes
+ attr_accessor :remotes
def initialize(options = {})
@options = options
@@ -96,7 +96,7 @@ module Bundler
def to_lock
out = String.new("GEM\n")
remotes.reverse_each do |remote|
- out << " remote: #{suppress_configured_credentials remote}\n"
+ out << " remote: #{remove_auth remote}\n"
end
out << " specs:\n"
end
@@ -312,11 +312,7 @@ module Bundler
end
def credless_remotes
- if Bundler.settings[:allow_deployment_source_credential_changes]
- remotes.map(&method(:remove_auth))
- else
- remotes.map(&method(:suppress_configured_credentials))
- end
+ remotes.map(&method(:remove_auth))
end
def remotes_for_spec(spec)
@@ -355,15 +351,6 @@ module Bundler
uri
end
- def suppress_configured_credentials(remote)
- remote_nouser = remove_auth(remote)
- if remote.userinfo && remote.userinfo == Bundler.settings[remote_nouser]
- remote_nouser
- else
- remote
- end
- end
-
def remove_auth(remote)
if remote.user || remote.password
remote.dup.tap {|uri| uri.user = uri.password = nil }.to_s
diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb
index d85e1c1c01..bbaac33a95 100644
--- a/lib/bundler/source_list.rb
+++ b/lib/bundler/source_list.rb
@@ -157,7 +157,11 @@ module Bundler
end
def map_sources(replacement_sources)
- rubygems, git, plugin = [@rubygems_sources, @git_sources, @plugin_sources].map do |sources|
+ rubygems = @rubygems_sources.map do |source|
+ replace_rubygems_source(replacement_sources, source) || source
+ end
+
+ git, plugin = [@git_sources, @plugin_sources].map do |sources|
sources.map do |source|
replacement_sources.find {|s| s == source } || source
end
@@ -171,13 +175,22 @@ module Bundler
end
def global_replacement_source(replacement_sources)
- replacement_source = replacement_sources.find {|s| s == global_rubygems_source }
+ replacement_source = replace_rubygems_source(replacement_sources, global_rubygems_source)
return global_rubygems_source unless replacement_source
replacement_source.cached!
replacement_source
end
+ def replace_rubygems_source(replacement_sources, gemfile_source)
+ replacement_source = replacement_sources.find {|s| s == gemfile_source }
+ return unless replacement_source
+
+ # locked sources never include credentials so always prefer remotes from the gemfile
+ replacement_source.remotes = gemfile_source.remotes
+ replacement_source
+ end
+
def different_sources?(lock_sources, replacement_sources)
!equivalent_sources?(lock_sources, replacement_sources)
end
diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb
index 2933d28450..8e1130e40e 100644
--- a/lib/bundler/spec_set.rb
+++ b/lib/bundler/spec_set.rb
@@ -129,6 +129,7 @@ module Bundler
def materialized_for_all_platforms
@specs.map do |s|
next s unless s.is_a?(LazySpecification)
+ s.source.cached!
s.source.remote!
spec = s.materialize_for_installation
raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec
diff --git a/lib/did_you_mean/did_you_mean.gemspec b/lib/did_you_mean/did_you_mean.gemspec
index 8fe5723129..be4ac76b4b 100644
--- a/lib/did_you_mean/did_you_mean.gemspec
+++ b/lib/did_you_mean/did_you_mean.gemspec
@@ -22,6 +22,4 @@ Gem::Specification.new do |spec|
spec.require_paths = ["lib"]
spec.required_ruby_version = '>= 2.5.0'
-
- spec.add_development_dependency "rake"
end
diff --git a/lib/find.gemspec b/lib/find.gemspec
index cb845e9409..aef24a5028 100644
--- a/lib/find.gemspec
+++ b/lib/find.gemspec
@@ -25,7 +25,5 @@ Gem::Specification.new do |spec|
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/ipaddr.rb b/lib/ipaddr.rb
index c1073ecd2b..dbb213c90a 100644
--- a/lib/ipaddr.rb
+++ b/lib/ipaddr.rb
@@ -227,6 +227,12 @@ class IPAddr
return str
end
+ # Returns a string containing the IP address representation in
+ # cidr notation
+ def cidr
+ format("%s/%s", to_s, prefix)
+ end
+
# Returns a network byte ordered string form of the IP address.
def hton
case @family
diff --git a/lib/irb.rb b/lib/irb.rb
index ab50c797c7..b3435c257e 100644
--- a/lib/irb.rb
+++ b/lib/irb.rb
@@ -311,7 +311,9 @@ require_relative "irb/pager"
# ### Input Method
#
# The IRB input method determines how command input is to be read; by default,
-# the input method for a session is IRB::RelineInputMethod.
+# the input method for a session is IRB::RelineInputMethod. Unless the
+# value of the TERM environment variable is 'dumb', in which case the
+# most simplistic input method is used.
#
# You can set the input method by:
#
@@ -329,7 +331,8 @@ require_relative "irb/pager"
# IRB::ReadlineInputMethod.
# * `--nosingleline` or `--multiline` sets the input method to
# IRB::RelineInputMethod.
-#
+# * `--nosingleline` together with `--nomultiline` sets the
+# input to IRB::StdioInputMethod.
#
#
# Method `conf.use_multiline?` and its synonym `conf.use_reline` return:
@@ -656,8 +659,10 @@ require_relative "irb/pager"
# * `%m`: the value of `self.to_s`.
# * `%M`: the value of `self.inspect`.
# * `%l`: an indication of the type of string; one of `"`, `'`, `/`, `]`.
-# * `*NN*i`: Indentation level.
-# * `*NN*n`: Line number.
+# * `%NNi`: Indentation level. NN is a 2-digit number that specifies the number
+# of digits of the indentation level (03 will result in 001).
+# * `%NNn`: Line number. NN is a 2-digit number that specifies the number
+# of digits of the line number (03 will result in 001).
# * `%%`: Literal `%`.
#
#
@@ -926,8 +931,11 @@ module IRB
# The lexer used by this irb session
attr_accessor :scanner
+ attr_reader :from_binding
+
# Creates a new irb session
- def initialize(workspace = nil, input_method = nil)
+ def initialize(workspace = nil, input_method = nil, from_binding: false)
+ @from_binding = from_binding
@context = Context.new(self, workspace, input_method)
@context.workspace.load_helper_methods_to_main
@signal_status = :IN_IRB
@@ -960,20 +968,26 @@ module IRB
#
# Irb#eval_input will simply return the input, and we need to pass it to the
# debugger.
- input = if IRB.conf[:SAVE_HISTORY] && context.io.support_history_saving?
- # Previous IRB session's history has been saved when `Irb#run` is exited We need
- # to make sure the saved history is not saved again by resetting the counter
- context.io.reset_history_counter
+ input = nil
+ forced_exit = catch(:IRB_EXIT) do
+ if IRB.conf[:SAVE_HISTORY] && context.io.support_history_saving?
+ # Previous IRB session's history has been saved when `Irb#run` is exited We need
+ # to make sure the saved history is not saved again by resetting the counter
+ context.io.reset_history_counter
- begin
- eval_input
- ensure
- context.io.save_history
+ begin
+ input = eval_input
+ ensure
+ context.io.save_history
+ end
+ else
+ input = eval_input
end
- else
- eval_input
+ false
end
+ Kernel.exit if forced_exit
+
if input&.include?("\n")
@line_no += input.count("\n") - 1
end
@@ -984,6 +998,7 @@ module IRB
def run(conf = IRB.conf)
in_nested_session = !!conf[:MAIN_CONTEXT]
conf[:IRB_RC].call(context) if conf[:IRB_RC]
+ prev_context = conf[:MAIN_CONTEXT]
conf[:MAIN_CONTEXT] = context
save_history = !in_nested_session && conf[:SAVE_HISTORY] && context.io.support_history_saving?
@@ -1006,6 +1021,9 @@ module IRB
eval_input
end
ensure
+ # Do not restore to nil. It will cause IRB crash when used with threads.
+ IRB.conf[:MAIN_CONTEXT] = prev_context if prev_context
+
RubyVM.keep_script_lines = keep_script_lines_backup if defined?(RubyVM.keep_script_lines)
trap("SIGINT", prev_trap)
conf[:AT_EXIT].each{|hook| hook.call}
@@ -1112,7 +1130,7 @@ module IRB
code.force_encoding(@context.io.encoding)
if (command, arg = parse_command(code))
- command_class = ExtendCommandBundle.load_command(command)
+ command_class = Command.load_command(command)
Statement::Command.new(code, command_class, arg)
else
is_assignment_expression = @scanner.assignment_expression?(code, local_variables: @context.local_variables)
@@ -1134,7 +1152,7 @@ module IRB
# Check visibility
public_method = !!Kernel.instance_method(:public_method).bind_call(@context.main, command) rescue false
private_method = !public_method && !!Kernel.instance_method(:method).bind_call(@context.main, command) rescue false
- if ExtendCommandBundle.execute_as_command?(command, public_method: public_method, private_method: private_method)
+ if Command.execute_as_command?(command, public_method: public_method, private_method: private_method)
[command, arg]
end
end
@@ -1230,27 +1248,33 @@ module IRB
irb_bug = true
else
irb_bug = false
- # This is mostly to make IRB work nicely with Rails console's backtrace filtering, which patches WorkSpace#filter_backtrace
- # In such use case, we want to filter the exception's backtrace before its displayed through Exception#full_message
- # And we clone the exception object in order to avoid mutating the original exception
- # TODO: introduce better API to expose exception backtrace externally
- backtrace = exc.backtrace.map { |l| @context.workspace.filter_backtrace(l) }.compact
+ # To support backtrace filtering while utilizing Exception#full_message, we need to clone
+ # the exception to avoid modifying the original exception's backtrace.
exc = exc.clone
- exc.set_backtrace(backtrace)
- end
+ filtered_backtrace = exc.backtrace.map { |l| @context.workspace.filter_backtrace(l) }.compact
+ backtrace_filter = IRB.conf[:BACKTRACE_FILTER]
- if RUBY_VERSION < '3.0.0'
- if STDOUT.tty?
- message = exc.full_message(order: :bottom)
- order = :bottom
- else
- message = exc.full_message(order: :top)
- order = :top
+ if backtrace_filter
+ if backtrace_filter.respond_to?(:call)
+ filtered_backtrace = backtrace_filter.call(filtered_backtrace)
+ else
+ warn "IRB.conf[:BACKTRACE_FILTER] #{backtrace_filter} should respond to `call` method"
+ end
end
- else # '3.0.0' <= RUBY_VERSION
- message = exc.full_message(order: :top)
- order = :top
+
+ exc.set_backtrace(filtered_backtrace)
end
+
+ highlight = Color.colorable?
+
+ order =
+ if RUBY_VERSION < '3.0.0'
+ STDOUT.tty? ? :bottom : :top
+ else # '3.0.0' <= RUBY_VERSION
+ :top
+ end
+
+ message = exc.full_message(order: order, highlight: highlight)
message = convert_invalid_byte_sequence(message, exc.message.encoding)
message = encode_with_invalid_byte_sequence(message, IRB.conf[:LC_MESSAGES].encoding) unless message.encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s)
message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
@@ -1455,7 +1479,7 @@ module IRB
end
def format_prompt(format, ltype, indent, line_no) # :nodoc:
- format.gsub(/%([0-9]+)?([a-zA-Z])/) do
+ format.gsub(/%([0-9]+)?([a-zA-Z%])/) do
case $2
when "N"
@context.irb_name
@@ -1488,7 +1512,7 @@ module IRB
line_no.to_s
end
when "%"
- "%"
+ "%" unless $1
end
end
end
@@ -1575,7 +1599,7 @@ class Binding
else
# If we're not in a debugger session, create a new IRB instance with the current
# workspace
- binding_irb = IRB::Irb.new(workspace)
+ binding_irb = IRB::Irb.new(workspace, from_binding: true)
binding_irb.context.irb_path = irb_path
binding_irb.run(IRB.conf)
binding_irb.debug_break
diff --git a/lib/irb/color.rb b/lib/irb/color.rb
index ad8670160c..fca942b28b 100644
--- a/lib/irb/color.rb
+++ b/lib/irb/color.rb
@@ -79,12 +79,12 @@ module IRB # :nodoc:
class << self
def colorable?
- supported = $stdout.tty? && (/mswin|mingw/ =~ RUBY_PLATFORM || (ENV.key?('TERM') && ENV['TERM'] != 'dumb'))
+ supported = $stdout.tty? && (/mswin|mingw/.match?(RUBY_PLATFORM) || (ENV.key?('TERM') && ENV['TERM'] != 'dumb'))
# because ruby/debug also uses irb's color module selectively,
# irb won't be activated in that case.
if IRB.respond_to?(:conf)
- supported && IRB.conf.fetch(:USE_COLORIZE, true)
+ supported && !!IRB.conf.fetch(:USE_COLORIZE, true)
else
supported
end
diff --git a/lib/irb/command.rb b/lib/irb/command.rb
index 19fde56356..68a4b52727 100644
--- a/lib/irb/command.rb
+++ b/lib/irb/command.rb
@@ -16,13 +16,7 @@ module IRB # :nodoc:
# Registers a command with the given name.
# Aliasing is intentionally not supported at the moment.
def register(name, command_class)
- @commands[name] = [command_class, []]
- end
-
- # This API is for IRB's internal use only and may change at any time.
- # Please do NOT use it.
- def _register_with_aliases(name, command_class, *aliases)
- @commands[name] = [command_class, aliases]
+ @commands[name.to_sym] = [command_class, []]
end
end
end
diff --git a/lib/irb/command/base.rb b/lib/irb/command/base.rb
index b078b48237..1d406630a2 100644
--- a/lib/irb/command/base.rb
+++ b/lib/irb/command/base.rb
@@ -18,12 +18,12 @@ module IRB
class << self
def category(category = nil)
@category = category if category
- @category
+ @category || "No category"
end
def description(description = nil)
@description = description if description
- @description
+ @description || "No description provided."
end
def help_message(help_message = nil)
diff --git a/lib/irb/command/chws.rb b/lib/irb/command/chws.rb
index e0a406885f..ef456d0961 100644
--- a/lib/irb/command/chws.rb
+++ b/lib/irb/command/chws.rb
@@ -15,7 +15,7 @@ module IRB
description "Show the current workspace."
def execute(_arg)
- irb_context.main
+ puts "Current workspace: #{irb_context.main}"
end
end
@@ -30,7 +30,8 @@ module IRB
obj = eval(arg, irb_context.workspace.binding)
irb_context.change_workspace(obj)
end
- irb_context.main
+
+ puts "Current workspace: #{irb_context.main}"
end
end
end
diff --git a/lib/irb/command/debug.rb b/lib/irb/command/debug.rb
index f9aca0a672..8a091a49ed 100644
--- a/lib/irb/command/debug.rb
+++ b/lib/irb/command/debug.rb
@@ -8,11 +8,6 @@ module IRB
category "Debugging"
description "Start the debugger of debug.gem."
- BINDING_IRB_FRAME_REGEXPS = [
- '<internal:prelude>',
- binding.method(:irb).source_location.first,
- ].map { |file| /\A#{Regexp.escape(file)}:\d+:in (`|'Binding#)irb'\z/ }
-
def execute(_arg)
execute_debug_command
end
@@ -36,7 +31,7 @@ module IRB
# 3. Insert a debug breakpoint at `Irb#debug_break` with the intended command.
# 4. Exit the current Irb#run call via `throw :IRB_EXIT`.
# 5. `Irb#debug_break` will be called and trigger the breakpoint, which will run the intended command.
- unless binding_irb?
+ unless irb_context.from_binding?
puts "Debugging commands are only available when IRB is started with binding.irb"
return
end
@@ -60,16 +55,6 @@ module IRB
throw :IRB_EXIT
end
end
-
- private
-
- def binding_irb?
- caller.any? do |frame|
- BINDING_IRB_FRAME_REGEXPS.any? do |regexp|
- frame.match?(regexp)
- end
- end
- end
end
class DebugCommand < Debug
diff --git a/lib/irb/command/exit.rb b/lib/irb/command/exit.rb
index 3109ec16e3..b4436f0343 100644
--- a/lib/irb/command/exit.rb
+++ b/lib/irb/command/exit.rb
@@ -8,10 +8,8 @@ module IRB
category "IRB"
description "Exit the current irb session."
- def execute(*)
+ def execute(_arg)
IRB.irb_exit
- rescue UncaughtThrowError
- Kernel.exit
end
end
end
diff --git a/lib/irb/command/force_exit.rb b/lib/irb/command/force_exit.rb
index c2c5542e24..14086aa849 100644
--- a/lib/irb/command/force_exit.rb
+++ b/lib/irb/command/force_exit.rb
@@ -8,10 +8,8 @@ module IRB
category "IRB"
description "Exit the current process."
- def execute(*)
+ def execute(_arg)
throw :IRB_EXIT, true
- rescue UncaughtThrowError
- Kernel.exit!
end
end
end
diff --git a/lib/irb/command/help.rb b/lib/irb/command/help.rb
index c9f16e05bc..c2018f9b30 100644
--- a/lib/irb/command/help.rb
+++ b/lib/irb/command/help.rb
@@ -11,7 +11,7 @@ module IRB
if command_name.empty?
help_message
else
- if command_class = ExtendCommandBundle.load_command(command_name)
+ if command_class = Command.load_command(command_name)
command_class.help_message || command_class.description
else
"Can't find command `#{command_name}`. Please check the command name and try again.\n\n"
@@ -23,20 +23,14 @@ module IRB
private
def help_message
- commands_info = IRB::ExtendCommandBundle.all_commands_info
+ commands_info = IRB::Command.all_commands_info
+ helper_methods_info = IRB::HelperMethod.all_helper_methods_info
commands_grouped_by_categories = commands_info.group_by { |cmd| cmd[:category] }
-
- user_aliases = irb_context.instance_variable_get(:@user_aliases)
-
- commands_grouped_by_categories["Aliases"] = user_aliases.map do |alias_name, target|
- { display_name: alias_name, description: "Alias for `#{target}`" }
- end
+ commands_grouped_by_categories["Helper methods"] = helper_methods_info
if irb_context.with_debugger
# Remove the original "Debugging" category
commands_grouped_by_categories.delete("Debugging")
- # Add an empty "Debugging (from debug.gem)" category at the end
- commands_grouped_by_categories["Debugging (from debug.gem)"] = []
end
longest_cmd_name_length = commands_info.map { |c| c[:display_name].length }.max
@@ -44,15 +38,31 @@ module IRB
output = StringIO.new
help_cmds = commands_grouped_by_categories.delete("Help")
+ no_category_cmds = commands_grouped_by_categories.delete("No category")
+ aliases = irb_context.instance_variable_get(:@user_aliases).map do |alias_name, target|
+ { display_name: alias_name, description: "Alias for `#{target}`" }
+ end
+ # Display help commands first
add_category_to_output("Help", help_cmds, output, longest_cmd_name_length)
+ # Display the rest of the commands grouped by categories
commands_grouped_by_categories.each do |category, cmds|
add_category_to_output(category, cmds, output, longest_cmd_name_length)
end
+ # Display commands without a category
+ if no_category_cmds
+ add_category_to_output("No category", no_category_cmds, output, longest_cmd_name_length)
+ end
+
+ # Display aliases
+ add_category_to_output("Aliases", aliases, output, longest_cmd_name_length)
+
# Append the debugger help at the end
if irb_context.with_debugger
+ # Add "Debugging (from debug.gem)" category as title
+ add_category_to_output("Debugging (from debug.gem)", [], output, longest_cmd_name_length)
output.puts DEBUGGER__.help
end
diff --git a/lib/irb/command/subirb.rb b/lib/irb/command/subirb.rb
index 138d61c930..85af28c1a5 100644
--- a/lib/irb/command/subirb.rb
+++ b/lib/irb/command/subirb.rb
@@ -49,6 +49,7 @@ module IRB
extend_irb_context
IRB.irb(nil, *obj)
+ puts IRB.JobManager.inspect
end
end
@@ -65,7 +66,7 @@ module IRB
end
extend_irb_context
- IRB.JobManager
+ puts IRB.JobManager.inspect
end
end
@@ -90,6 +91,7 @@ module IRB
raise CommandArgumentError.new("Please specify the id of target IRB job (listed in the `jobs` command).") unless key
IRB.JobManager.switch(key)
+ puts IRB.JobManager.inspect
end
end
@@ -112,6 +114,7 @@ module IRB
extend_irb_context
IRB.JobManager.kill(*keys)
+ puts IRB.JobManager.inspect
end
end
end
diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb
index 8a1df11561..a3d89373c3 100644
--- a/lib/irb/completion.rb
+++ b/lib/irb/completion.rb
@@ -88,7 +88,7 @@ module IRB
def command_completions(preposing, target)
if preposing.empty? && !target.empty?
- IRB::ExtendCommandBundle.command_names.select { _1.start_with?(target) }
+ IRB::Command.command_names.select { _1.start_with?(target) }
else
[]
end
diff --git a/lib/irb/context.rb b/lib/irb/context.rb
index 836b8d2625..aafce7aade 100644
--- a/lib/irb/context.rb
+++ b/lib/irb/context.rb
@@ -73,11 +73,12 @@ module IRB
self.prompt_mode = IRB.conf[:PROMPT_MODE]
- if IRB.conf[:SINGLE_IRB] or !defined?(IRB::JobManager)
- @irb_name = IRB.conf[:IRB_NAME]
- else
- @irb_name = IRB.conf[:IRB_NAME]+"#"+IRB.JobManager.n_jobs.to_s
+ @irb_name = IRB.conf[:IRB_NAME]
+
+ unless IRB.conf[:SINGLE_IRB] or !defined?(IRB::JobManager)
+ @irb_name = @irb_name + "#" + IRB.JobManager.n_jobs.to_s
end
+
self.irb_path = "(" + @irb_name + ")"
case input_method
@@ -85,7 +86,7 @@ module IRB
@io = nil
case use_multiline?
when nil
- if STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
+ if term_interactive? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
# Both of multiline mode and singleline mode aren't specified.
@io = RelineInputMethod.new(build_completor)
else
@@ -99,7 +100,7 @@ module IRB
unless @io
case use_singleline?
when nil
- if (defined?(ReadlineInputMethod) && STDIN.tty? &&
+ if (defined?(ReadlineInputMethod) && term_interactive? &&
IRB.conf[:PROMPT_MODE] != :INF_RUBY)
@io = ReadlineInputMethod.new
else
@@ -151,6 +152,11 @@ module IRB
@command_aliases = @user_aliases.merge(KEYWORD_ALIASES)
end
+ private def term_interactive?
+ return true if ENV['TEST_IRB_FORCE_INTERACTIVE']
+ STDIN.tty? && ENV['TERM'] != 'dumb'
+ end
+
# because all input will eventually be evaluated as Ruby code,
# command names that conflict with Ruby keywords need special workaround
# we can remove them once we implemented a better command system for IRB
@@ -587,18 +593,23 @@ module IRB
def evaluate(statement, line_no) # :nodoc:
@line_no = line_no
- result = nil
case statement
when Statement::EmptyInput
return
when Statement::Expression
result = evaluate_expression(statement.code, line_no)
+ set_last_value(result)
when Statement::Command
- result = statement.command_class.execute(self, statement.arg)
+ statement.command_class.execute(self, statement.arg)
+ set_last_value(nil)
end
- set_last_value(result)
+ nil
+ end
+
+ def from_binding?
+ @irb.from_binding
end
def evaluate_expression(code, line_no) # :nodoc:
diff --git a/lib/irb/default_commands.rb b/lib/irb/default_commands.rb
index d680655fee..1bbc68efa7 100644
--- a/lib/irb/default_commands.rb
+++ b/lib/irb/default_commands.rb
@@ -30,35 +30,88 @@ require_relative "command/whereami"
require_relative "command/history"
module IRB
- ExtendCommand = Command
-
- # Installs the default irb extensions command bundle.
- module ExtendCommandBundle
- # See #install_alias_method.
+ module Command
NO_OVERRIDE = 0
- # See #install_alias_method.
OVERRIDE_PRIVATE_ONLY = 0x01
- # See #install_alias_method.
OVERRIDE_ALL = 0x02
- Command._register_with_aliases(:irb_context, Command::Context,
- [
- [:context, NO_OVERRIDE],
- [:conf, NO_OVERRIDE],
- ],
+ class << self
+ # This API is for IRB's internal use only and may change at any time.
+ # Please do NOT use it.
+ def _register_with_aliases(name, command_class, *aliases)
+ @commands[name.to_sym] = [command_class, aliases]
+ end
+
+ def all_commands_info
+ user_aliases = IRB.CurrentContext.command_aliases.each_with_object({}) do |(alias_name, target), result|
+ result[target] ||= []
+ result[target] << alias_name
+ end
+
+ commands.map do |command_name, (command_class, aliases)|
+ aliases = aliases.map { |a| a.first }
+
+ if additional_aliases = user_aliases[command_name]
+ aliases += additional_aliases
+ end
+
+ display_name = aliases.shift || command_name
+ {
+ display_name: display_name,
+ description: command_class.description,
+ category: command_class.category
+ }
+ end
+ end
+
+ def command_override_policies
+ @@command_override_policies ||= commands.flat_map do |cmd_name, (cmd_class, aliases)|
+ [[cmd_name, OVERRIDE_ALL]] + aliases
+ end.to_h
+ end
+
+ def execute_as_command?(name, public_method:, private_method:)
+ case command_override_policies[name]
+ when OVERRIDE_ALL
+ true
+ when OVERRIDE_PRIVATE_ONLY
+ !public_method
+ when NO_OVERRIDE
+ !public_method && !private_method
+ end
+ end
+
+ def command_names
+ command_override_policies.keys.map(&:to_s)
+ end
+
+ # Convert a command name to its implementation class if such command exists
+ def load_command(command)
+ command = command.to_sym
+ commands.each do |command_name, (command_class, aliases)|
+ if command_name == command || aliases.any? { |alias_name, _| alias_name == command }
+ return command_class
+ end
+ end
+ nil
+ end
+ end
+
+ _register_with_aliases(:irb_context, Command::Context,
+ [:context, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_exit, Command::Exit,
+ _register_with_aliases(:irb_exit, Command::Exit,
[:exit, OVERRIDE_PRIVATE_ONLY],
[:quit, OVERRIDE_PRIVATE_ONLY],
[:irb_quit, OVERRIDE_PRIVATE_ONLY]
)
- Command._register_with_aliases(:irb_exit!, Command::ForceExit,
+ _register_with_aliases(:irb_exit!, Command::ForceExit,
[:exit!, OVERRIDE_PRIVATE_ONLY]
)
- Command._register_with_aliases(:irb_current_working_workspace, Command::CurrentWorkingWorkspace,
+ _register_with_aliases(:irb_current_working_workspace, Command::CurrentWorkingWorkspace,
[:cwws, NO_OVERRIDE],
[:pwws, NO_OVERRIDE],
[:irb_print_working_workspace, OVERRIDE_ALL],
@@ -70,7 +123,7 @@ module IRB
[:irb_pwb, OVERRIDE_ALL],
)
- Command._register_with_aliases(:irb_change_workspace, Command::ChangeWorkspace,
+ _register_with_aliases(:irb_change_workspace, Command::ChangeWorkspace,
[:chws, NO_OVERRIDE],
[:cws, NO_OVERRIDE],
[:irb_chws, OVERRIDE_ALL],
@@ -80,13 +133,13 @@ module IRB
[:cb, NO_OVERRIDE],
)
- Command._register_with_aliases(:irb_workspaces, Command::Workspaces,
+ _register_with_aliases(:irb_workspaces, Command::Workspaces,
[:workspaces, NO_OVERRIDE],
[:irb_bindings, OVERRIDE_ALL],
[:bindings, NO_OVERRIDE],
)
- Command._register_with_aliases(:irb_push_workspace, Command::PushWorkspace,
+ _register_with_aliases(:irb_push_workspace, Command::PushWorkspace,
[:pushws, NO_OVERRIDE],
[:irb_pushws, OVERRIDE_ALL],
[:irb_push_binding, OVERRIDE_ALL],
@@ -94,7 +147,7 @@ module IRB
[:pushb, NO_OVERRIDE],
)
- Command._register_with_aliases(:irb_pop_workspace, Command::PopWorkspace,
+ _register_with_aliases(:irb_pop_workspace, Command::PopWorkspace,
[:popws, NO_OVERRIDE],
[:irb_popws, OVERRIDE_ALL],
[:irb_pop_binding, OVERRIDE_ALL],
@@ -102,140 +155,98 @@ module IRB
[:popb, NO_OVERRIDE],
)
- Command._register_with_aliases(:irb_load, Command::Load)
- Command._register_with_aliases(:irb_require, Command::Require)
- Command._register_with_aliases(:irb_source, Command::Source,
+ _register_with_aliases(:irb_load, Command::Load)
+ _register_with_aliases(:irb_require, Command::Require)
+ _register_with_aliases(:irb_source, Command::Source,
[:source, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb, Command::IrbCommand)
- Command._register_with_aliases(:irb_jobs, Command::Jobs,
+ _register_with_aliases(:irb, Command::IrbCommand)
+ _register_with_aliases(:irb_jobs, Command::Jobs,
[:jobs, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_fg, Command::Foreground,
+ _register_with_aliases(:irb_fg, Command::Foreground,
[:fg, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_kill, Command::Kill,
+ _register_with_aliases(:irb_kill, Command::Kill,
[:kill, OVERRIDE_PRIVATE_ONLY]
)
- Command._register_with_aliases(:irb_debug, Command::Debug,
+ _register_with_aliases(:irb_debug, Command::Debug,
[:debug, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_edit, Command::Edit,
+ _register_with_aliases(:irb_edit, Command::Edit,
[:edit, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_break, Command::Break)
- Command._register_with_aliases(:irb_catch, Command::Catch)
- Command._register_with_aliases(:irb_next, Command::Next)
- Command._register_with_aliases(:irb_delete, Command::Delete,
+ _register_with_aliases(:irb_break, Command::Break)
+ _register_with_aliases(:irb_catch, Command::Catch)
+ _register_with_aliases(:irb_next, Command::Next)
+ _register_with_aliases(:irb_delete, Command::Delete,
[:delete, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_step, Command::Step,
+ _register_with_aliases(:irb_step, Command::Step,
[:step, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_continue, Command::Continue,
+ _register_with_aliases(:irb_continue, Command::Continue,
[:continue, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_finish, Command::Finish,
+ _register_with_aliases(:irb_finish, Command::Finish,
[:finish, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_backtrace, Command::Backtrace,
+ _register_with_aliases(:irb_backtrace, Command::Backtrace,
[:backtrace, NO_OVERRIDE],
[:bt, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_debug_info, Command::Info,
+ _register_with_aliases(:irb_debug_info, Command::Info,
[:info, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_help, Command::Help,
+ _register_with_aliases(:irb_help, Command::Help,
[:help, NO_OVERRIDE],
[:show_cmds, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_show_doc, Command::ShowDoc,
+ _register_with_aliases(:irb_show_doc, Command::ShowDoc,
[:show_doc, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_info, Command::IrbInfo)
+ _register_with_aliases(:irb_info, Command::IrbInfo)
- Command._register_with_aliases(:irb_ls, Command::Ls,
+ _register_with_aliases(:irb_ls, Command::Ls,
[:ls, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_measure, Command::Measure,
+ _register_with_aliases(:irb_measure, Command::Measure,
[:measure, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_show_source, Command::ShowSource,
+ _register_with_aliases(:irb_show_source, Command::ShowSource,
[:show_source, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_whereami, Command::Whereami,
+ _register_with_aliases(:irb_whereami, Command::Whereami,
[:whereami, NO_OVERRIDE]
)
- Command._register_with_aliases(:irb_history, Command::History,
+ _register_with_aliases(:irb_history, Command::History,
[:history, NO_OVERRIDE],
[:hist, NO_OVERRIDE]
)
+ end
- def self.all_commands_info
- user_aliases = IRB.CurrentContext.command_aliases.each_with_object({}) do |(alias_name, target), result|
- result[target] ||= []
- result[target] << alias_name
- end
-
- Command.commands.map do |command_name, (command_class, aliases)|
- aliases = aliases.map { |a| a.first }
-
- if additional_aliases = user_aliases[command_name]
- aliases += additional_aliases
- end
-
- display_name = aliases.shift || command_name
- {
- display_name: display_name,
- description: command_class.description,
- category: command_class.category
- }
- end
- end
-
- def self.command_override_policies
- @@command_override_policies ||= Command.commands.flat_map do |cmd_name, (cmd_class, aliases)|
- [[cmd_name, OVERRIDE_ALL]] + aliases
- end.to_h
- end
-
- def self.execute_as_command?(name, public_method:, private_method:)
- case command_override_policies[name]
- when OVERRIDE_ALL
- true
- when OVERRIDE_PRIVATE_ONLY
- !public_method
- when NO_OVERRIDE
- !public_method && !private_method
- end
- end
-
- def self.command_names
- command_override_policies.keys.map(&:to_s)
- end
+ ExtendCommand = Command
- # Convert a command name to its implementation class if such command exists
- def self.load_command(command)
- command = command.to_sym
- Command.commands.each do |command_name, (command_class, aliases)|
- if command_name == command || aliases.any? { |alias_name, _| alias_name == command }
- return command_class
- end
- end
- nil
- end
+ # For backward compatibility, we need to keep this module:
+ # - As a container of helper methods
+ # - As a place to register commands with the deprecated def_extend_command method
+ module ExtendCommandBundle
+ # For backward compatibility
+ NO_OVERRIDE = Command::NO_OVERRIDE
+ OVERRIDE_PRIVATE_ONLY = Command::OVERRIDE_PRIVATE_ONLY
+ OVERRIDE_ALL = Command::OVERRIDE_ALL
# Deprecated. Doesn't have any effect.
@EXTEND_COMMANDS = []
@@ -243,7 +254,7 @@ module IRB
# Drepcated. Use Command.regiser instead.
def self.def_extend_command(cmd_name, cmd_class, _, *aliases)
Command._register_with_aliases(cmd_name, cmd_class, *aliases)
- @@command_override_policies = nil
+ Command.class_variable_set(:@@command_override_policies, nil)
end
end
end
diff --git a/lib/irb/helper_method.rb b/lib/irb/helper_method.rb
new file mode 100644
index 0000000000..f1f6fff915
--- /dev/null
+++ b/lib/irb/helper_method.rb
@@ -0,0 +1,29 @@
+require_relative "helper_method/base"
+
+module IRB
+ module HelperMethod
+ @helper_methods = {}
+
+ class << self
+ attr_reader :helper_methods
+
+ def register(name, helper_class)
+ @helper_methods[name] = helper_class
+
+ if defined?(HelpersContainer)
+ HelpersContainer.install_helper_methods
+ end
+ end
+
+ def all_helper_methods_info
+ @helper_methods.map do |name, helper_class|
+ { display_name: name, description: helper_class.description }
+ end
+ end
+ end
+
+ # Default helper_methods
+ require_relative "helper_method/conf"
+ register(:conf, HelperMethod::Conf)
+ end
+end
diff --git a/lib/irb/helper_method/base.rb b/lib/irb/helper_method/base.rb
new file mode 100644
index 0000000000..a68001ed28
--- /dev/null
+++ b/lib/irb/helper_method/base.rb
@@ -0,0 +1,16 @@
+require "singleton"
+
+module IRB
+ module HelperMethod
+ class Base
+ include Singleton
+
+ class << self
+ def description(description = nil)
+ @description = description if description
+ @description
+ end
+ end
+ end
+ end
+end
diff --git a/lib/irb/helper_method/conf.rb b/lib/irb/helper_method/conf.rb
new file mode 100644
index 0000000000..718ed279c0
--- /dev/null
+++ b/lib/irb/helper_method/conf.rb
@@ -0,0 +1,11 @@
+module IRB
+ module HelperMethod
+ class Conf < Base
+ description "Returns the current IRB context."
+
+ def execute
+ IRB.CurrentContext
+ end
+ end
+ end
+end
diff --git a/lib/irb/init.rb b/lib/irb/init.rb
index 355047519c..7dc08912ef 100644
--- a/lib/irb/init.rb
+++ b/lib/irb/init.rb
@@ -52,6 +52,7 @@ module IRB # :nodoc:
IRB.init_error
IRB.parse_opts(argv: argv)
IRB.run_config
+ IRB.validate_config
IRB.load_modules
unless @CONF[:PROMPT][@CONF[:PROMPT_MODE]]
@@ -427,6 +428,40 @@ module IRB # :nodoc:
@irbrc_files
end
+ def IRB.validate_config
+ conf[:IRB_NAME] = conf[:IRB_NAME].to_s
+
+ irb_rc = conf[:IRB_RC]
+ unless irb_rc.nil? || irb_rc.respond_to?(:call)
+ raise_validation_error "IRB.conf[:IRB_RC] should be a callable object. Got #{irb_rc.inspect}."
+ end
+
+ back_trace_limit = conf[:BACK_TRACE_LIMIT]
+ unless back_trace_limit.is_a?(Integer)
+ raise_validation_error "IRB.conf[:BACK_TRACE_LIMIT] should be an integer. Got #{back_trace_limit.inspect}."
+ end
+
+ prompt = conf[:PROMPT]
+ unless prompt.is_a?(Hash)
+ msg = "IRB.conf[:PROMPT] should be a Hash. Got #{prompt.inspect}."
+
+ if prompt.is_a?(Symbol)
+ msg += " Did you mean to set `IRB.conf[:PROMPT_MODE]`?"
+ end
+
+ raise_validation_error msg
+ end
+
+ eval_history = conf[:EVAL_HISTORY]
+ unless eval_history.nil? || eval_history.is_a?(Integer)
+ raise_validation_error "IRB.conf[:EVAL_HISTORY] should be an integer. Got #{eval_history.inspect}."
+ end
+ end
+
+ def IRB.raise_validation_error(msg)
+ raise TypeError, msg, @irbrc_files
+ end
+
# loading modules
def IRB.load_modules
for m in @CONF[:LOAD_MODULES]
diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb
index e5adb350e8..684527edc4 100644
--- a/lib/irb/input-method.rb
+++ b/lib/irb/input-method.rb
@@ -67,6 +67,7 @@ module IRB
#
# See IO#gets for more information.
def gets
+ puts if @stdout.tty? # workaround for debug compatibility test
print @prompt
line = @stdin.gets
@line[@line_no += 1] = line
diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb
index cfe36be83f..f6ac7f0f5f 100644
--- a/lib/irb/ruby-lex.rb
+++ b/lib/irb/ruby-lex.rb
@@ -219,28 +219,7 @@ module IRB
:unrecoverable_error
rescue SyntaxError => e
case e.message
- when /unterminated (?:string|regexp) meets end of file/
- # "unterminated regexp meets end of file"
- #
- # example:
- # /
- #
- # "unterminated string meets end of file"
- #
- # example:
- # '
- return :recoverable_error
- when /syntax error, unexpected end-of-input/
- # "syntax error, unexpected end-of-input, expecting keyword_end"
- #
- # example:
- # if true
- # hoge
- # if false
- # fuga
- # end
- return :recoverable_error
- when /syntax error, unexpected keyword_end/
+ when /unexpected keyword_end/
# "syntax error, unexpected keyword_end"
#
# example:
@@ -250,7 +229,7 @@ module IRB
# example:
# end
return :unrecoverable_error
- when /syntax error, unexpected '\.'/
+ when /unexpected '\.'/
# "syntax error, unexpected '.'"
#
# example:
@@ -262,6 +241,27 @@ module IRB
# example:
# method / f /
return :unrecoverable_error
+ when /unterminated (?:string|regexp) meets end of file/
+ # "unterminated regexp meets end of file"
+ #
+ # example:
+ # /
+ #
+ # "unterminated string meets end of file"
+ #
+ # example:
+ # '
+ return :recoverable_error
+ when /unexpected end-of-input/
+ # "syntax error, unexpected end-of-input, expecting keyword_end"
+ #
+ # example:
+ # if true
+ # hoge
+ # if false
+ # fuga
+ # end
+ return :recoverable_error
else
return :other_error
end
diff --git a/lib/irb/version.rb b/lib/irb/version.rb
index 9a7b12766b..c41917329c 100644
--- a/lib/irb/version.rb
+++ b/lib/irb/version.rb
@@ -5,7 +5,7 @@
#
module IRB # :nodoc:
- VERSION = "1.12.0"
+ VERSION = "1.13.1"
@RELEASE_VERSION = VERSION
- @LAST_UPDATE_DATE = "2024-03-06"
+ @LAST_UPDATE_DATE = "2024-05-05"
end
diff --git a/lib/irb/workspace.rb b/lib/irb/workspace.rb
index 1490f7b478..d24d1cc38d 100644
--- a/lib/irb/workspace.rb
+++ b/lib/irb/workspace.rb
@@ -6,6 +6,8 @@
require "delegate"
+require_relative "helper_method"
+
IRB::TOPLEVEL_BINDING = binding
module IRB # :nodoc:
class WorkSpace
@@ -109,9 +111,9 @@ EOF
attr_reader :main
def load_helper_methods_to_main
- if !(class<<main;ancestors;end).include?(ExtendCommandBundle)
- main.extend ExtendCommandBundle
- end
+ ancestors = class<<main;ancestors;end
+ main.extend ExtendCommandBundle if !ancestors.include?(ExtendCommandBundle)
+ main.extend HelpersContainer if !ancestors.include?(HelpersContainer)
end
# Evaluate the given +statements+ within the context of this workspace.
@@ -172,4 +174,16 @@ EOF
"\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear}\n"
end
end
+
+ module HelpersContainer
+ def self.install_helper_methods
+ HelperMethod.helper_methods.each do |name, helper_method_class|
+ define_method name do |*args, **opts, &block|
+ helper_method_class.instance.execute(*args, **opts, &block)
+ end unless method_defined?(name)
+ end
+ end
+
+ install_helper_methods
+ end
end
diff --git a/lib/optparse/optparse.gemspec b/lib/optparse/optparse.gemspec
index a4287ddeee..1aa54aa781 100644
--- a/lib/optparse/optparse.gemspec
+++ b/lib/optparse/optparse.gemspec
@@ -22,7 +22,8 @@ Gem::Specification.new do |spec|
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
- spec.files = Dir["{doc,lib,misc}/**/*"] + %w[README.md ChangeLog COPYING]
+ spec.files = Dir["{doc,lib,misc}/**/{*,.document}"] +
+ %w[README.md ChangeLog COPYING .document .rdoc_options]
spec.rdoc_options = ["--main=README.md", "--op=rdoc", "--page-dir=doc"]
spec.bindir = "exe"
spec.executables = []
diff --git a/lib/prism.rb b/lib/prism.rb
index c512cb4015..2bb7f79bf6 100644
--- a/lib/prism.rb
+++ b/lib/prism.rb
@@ -18,10 +18,10 @@ module Prism
autoload :Dispatcher, "prism/dispatcher"
autoload :DotVisitor, "prism/dot_visitor"
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 :NodeInspector, "prism/node_inspector"
autoload :Pack, "prism/pack"
autoload :Pattern, "prism/pattern"
autoload :Reflection, "prism/reflection"
@@ -37,7 +37,7 @@ module Prism
private_constant :LexRipper
# :call-seq:
- # Prism::lex_compat(source, **options) -> ParseResult
+ # Prism::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
@@ -67,11 +67,10 @@ module Prism
end
end
+require_relative "prism/polyfill/byteindex"
require_relative "prism/node"
require_relative "prism/node_ext"
require_relative "prism/parse_result"
-require_relative "prism/parse_result/comments"
-require_relative "prism/parse_result/newlines"
# This is a Ruby implementation of the prism parser. If we're running on CRuby
# and we haven't explicitly set the PRISM_FFI_BACKEND environment variable, then
diff --git a/lib/prism/desugar_compiler.rb b/lib/prism/desugar_compiler.rb
index 9b62c00df3..de02445149 100644
--- a/lib/prism/desugar_compiler.rb
+++ b/lib/prism/desugar_compiler.rb
@@ -73,7 +73,7 @@ module Prism
# Desugar `x += y` to `x = x + y`
def compile
- operator_loc = node.operator_loc.chop
+ binary_operator_loc = node.binary_operator_loc.chop
write_class.new(
source,
@@ -84,15 +84,15 @@ module Prism
0,
read_class.new(source, *arguments, node.name_loc),
nil,
- operator_loc.slice.to_sym,
- operator_loc,
+ binary_operator_loc.slice.to_sym,
+ binary_operator_loc,
nil,
ArgumentsNode.new(source, 0, [node.value], node.value.location),
nil,
nil,
node.location
),
- node.operator_loc.copy(start_offset: node.operator_loc.end_offset - 1, length: 1),
+ node.binary_operator_loc.copy(start_offset: node.binary_operator_loc.end_offset - 1, length: 1),
node.location
)
end
diff --git a/lib/prism/ffi.rb b/lib/prism/ffi.rb
index 1fd053f902..b62a59d037 100644
--- a/lib/prism/ffi.rb
+++ b/lib/prism/ffi.rb
@@ -317,7 +317,7 @@ module Prism
buffer.read
end
- Serialize.load_tokens(Source.new(code), serialized)
+ Serialize.load_tokens(Source.for(code), serialized)
end
def parse_common(string, code, options) # :nodoc:
@@ -329,7 +329,7 @@ module Prism
LibRubyParser::PrismBuffer.with do |buffer|
LibRubyParser.pm_serialize_parse_comments(buffer.pointer, string.pointer, string.length, dump_options(options))
- source = Source.new(code)
+ source = Source.for(code)
loader = Serialize::Loader.new(source, buffer.read)
loader.load_header
@@ -343,14 +343,14 @@ module Prism
LibRubyParser::PrismBuffer.with do |buffer|
LibRubyParser.pm_serialize_parse_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
- source = Source.new(code)
+ source = Source.for(code)
loader = Serialize::Loader.new(source, buffer.read)
tokens = loader.load_tokens
node, comments, magic_comments, data_loc, errors, warnings = loader.load_nodes
tokens.each { |token,| token.value.force_encoding(loader.encoding) }
- ParseResult.new([node, tokens], comments, magic_comments, data_loc, errors, warnings, source)
+ ParseLexResult.new([node, tokens], comments, magic_comments, data_loc, errors, warnings, source)
end
end
@@ -408,7 +408,7 @@ module Prism
values << dump_options_command_line(options)
template << "C"
- values << { nil => 0, "3.3.0" => 1, "3.4.0" => 0, "latest" => 0 }.fetch(options[:version])
+ values << { nil => 0, "3.3.0" => 1, "3.3.1" => 1, "3.4.0" => 0, "latest" => 0 }.fetch(options[:version])
template << "L"
if (scopes = options[:scopes])
diff --git a/lib/prism/lex_compat.rb b/lib/prism/lex_compat.rb
index 70cb065201..4f8e443a3b 100644
--- a/lib/prism/lex_compat.rb
+++ b/lib/prism/lex_compat.rb
@@ -10,6 +10,23 @@ module Prism
# generally lines up. However, there are a few cases that require special
# handling.
class LexCompat # :nodoc:
+ # 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
+
+ # Create a new lex compat result object with the given values.
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
+ @value = value
+ super(comments, magic_comments, data_loc, errors, warnings, source)
+ end
+
+ # Implement the hash pattern matching interface for Result.
+ def deconstruct_keys(keys)
+ super.merge!(value: value)
+ end
+ end
+
# This is a mapping of prism token types to Ripper token types. This is a
# many-to-one mapping because we split up our token types, whereas Ripper
# tends to group them.
@@ -844,7 +861,7 @@ module Prism
# We sort by location to compare against Ripper's output
tokens.sort_by!(&:location)
- ParseResult.new(tokens, result.comments, result.magic_comments, result.data_loc, result.errors, result.warnings, Source.new(source))
+ Result.new(tokens, result.comments, result.magic_comments, result.data_loc, result.errors, result.warnings, Source.for(source))
end
end
diff --git a/lib/prism/node_ext.rb b/lib/prism/node_ext.rb
index 8674544065..ceec76b8d6 100644
--- a/lib/prism/node_ext.rb
+++ b/lib/prism/node_ext.rb
@@ -3,6 +3,17 @@
# 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
+ def deprecated(*replacements) # :nodoc:
+ suggest = replacements.map { |replacement| "#{self.class}##{replacement}" }
+ warn(<<~MSG, category: :deprecated)
+ [deprecation]: #{self.class}##{caller_locations(1, 1)[0].label} is deprecated \
+ and will be removed in the next major version. Use #{suggest.join("/")} instead.
+ #{(caller(1, 3) || []).join("\n")}
+ MSG
+ end
+ end
+
module RegularExpressionOptions # :nodoc:
# Returns a numeric value that represents the flags that were used to create
# the regular expression.
@@ -143,11 +154,12 @@ module Prism
current = self #: node?
while current.is_a?(ConstantPathNode)
- child = current.child
- if child.is_a?(MissingNode)
+ name = current.name
+ if name.nil?
raise MissingNodesInConstantPathError, "Constant path contains missing nodes. Cannot compute full name"
end
- parts.unshift(child.name)
+
+ parts.unshift(name)
current = current.parent
end
@@ -162,6 +174,14 @@ module Prism
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")
+ name ? ConstantReadNode.new(source, name, name_loc) : MissingNode.new(source, location)
+ end
end
class ConstantPathTargetNode < Node
@@ -179,17 +199,25 @@ module Prism
raise ConstantPathNode::DynamicPartsInConstantPathError, "Constant target path contains dynamic parts. Cannot compute full name"
end
- if child.is_a?(MissingNode)
+ if name.nil?
raise ConstantPathNode::MissingNodesInConstantPathError, "Constant target path contains missing nodes. Cannot compute full name"
end
- parts.push(child.name)
+ parts.push(name)
end
# Returns the full name of this constant path. For example: "Foo::Bar"
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")
+ name ? ConstantReadNode.new(source, name, name_loc) : MissingNode.new(source, location)
+ end
end
class ConstantTargetNode < Node
@@ -257,4 +285,147 @@ module Prism
names
end
end
+
+ class CallNode < Node
+ # When a call node has the attribute_write flag set, it means that the call
+ # is using the attribute write syntax. This is either a method call to []=
+ # or a method call to a method that ends with =. Either way, the = sign is
+ # present in the source.
+ #
+ # Prism returns the message_loc _without_ the = sign attached, because there
+ # 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.
+ 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
end
diff --git a/lib/prism/node_inspector.rb b/lib/prism/node_inspector.rb
deleted file mode 100644
index d77af33c3a..0000000000
--- a/lib/prism/node_inspector.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- # This object is responsible for generating the output for the inspect method
- # implementations of child nodes.
- class NodeInspector # :nodoc:
- attr_reader :prefix, :output
-
- def initialize(prefix = "")
- @prefix = prefix
- @output = +""
- end
-
- # Appends a line to the output with the current prefix.
- def <<(line)
- output << "#{prefix}#{line}"
- end
-
- # This generates a string that is used as the header of the inspect output
- # for any given node.
- def header(node)
- output = +"@ #{node.class.name.split("::").last} ("
- output << "location: (#{node.location.start_line},#{node.location.start_column})-(#{node.location.end_line},#{node.location.end_column})"
- output << ", newline: true" if node.newline?
- output << ")\n"
- output
- end
-
- # Generates a string that represents a list of nodes. It handles properly
- # using the box drawing characters to make the output look nice.
- def list(prefix, nodes)
- output = +"(length: #{nodes.length})\n"
- last_index = nodes.length - 1
-
- nodes.each_with_index do |node, index|
- pointer, preadd = (index == last_index) ? ["└── ", " "] : ["├── ", "│ "]
- node_prefix = "#{prefix}#{preadd}"
- output << node.inspect(NodeInspector.new(node_prefix)).sub(node_prefix, "#{prefix}#{pointer}")
- end
-
- output
- end
-
- # Generates a string that represents a location field on a node.
- def location(value)
- if value
- "(#{value.start_line},#{value.start_column})-(#{value.end_line},#{value.end_column}) = #{value.slice.inspect}"
- else
- "∅"
- end
- end
-
- # Generates a string that represents a child node.
- def child_node(node, append)
- node.inspect(child_inspector(append)).delete_prefix(prefix)
- end
-
- # Returns a new inspector that can be used to inspect a child node.
- def child_inspector(append)
- NodeInspector.new("#{prefix}#{append}")
- end
-
- # Returns the output as a string.
- def to_str
- output
- end
- end
-end
diff --git a/lib/prism/parse_result.rb b/lib/prism/parse_result.rb
index 39e15f6027..798fde09e5 100644
--- a/lib/prism/parse_result.rb
+++ b/lib/prism/parse_result.rb
@@ -5,6 +5,14 @@ module Prism
# conjunction with locations to allow them to resolve line numbers and source
# ranges.
class Source
+ # Create a new source object with the given source code. This method should
+ # 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 = [])
+ source.ascii_only? ? ASCIISource.new(source, start_line, offsets): new(source, start_line, offsets)
+ end
+
# The source code that this source object represents.
attr_reader :source
@@ -27,6 +35,11 @@ module Prism
source.encoding
end
+ # Returns the lines of the source code as an array of strings.
+ def lines
+ source.lines
+ end
+
# Perform a byteslice on the source code using the given byte offset and
# byte length.
def slice(byte_offset, length)
@@ -45,6 +58,12 @@ module Prism
offsets[find_line(byte_offset)]
end
+ # Returns the byte offset of the end of the line corresponding to the given
+ # byte offset.
+ def line_end(byte_offset)
+ offsets[find_line(byte_offset) + 1] || source.bytesize
+ end
+
# Return the column number for the given byte offset.
def column(byte_offset)
byte_offset - line_start(byte_offset)
@@ -100,6 +119,39 @@ module Prism
end
end
+ # Specialized version of Prism::Source for source code that includes ASCII
+ # characters only. This class is used to apply performance optimizations that
+ # cannot be applied to sources that include multibyte characters. Sources that
+ # include multibyte characters are represented by the Prism::Source class.
+ class ASCIISource < Source
+ # Return the character offset for the given byte offset.
+ def character_offset(byte_offset)
+ byte_offset
+ end
+
+ # Return the column number in characters for the given byte offset.
+ def character_column(byte_offset)
+ byte_offset - line_start(byte_offset)
+ end
+
+ # Returns the offset from the start of the file for the given byte offset
+ # counting in code units for the given encoding.
+ #
+ # 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.
+ def code_units_offset(byte_offset, encoding)
+ byte_offset
+ end
+
+ # Specialized version of `code_units_column` that does not depend on
+ # `code_units_offset`, which is a more expensive operation. This is
+ # essentialy the same as `Prism::Source#column`.
+ def code_units_column(byte_offset, encoding)
+ byte_offset - line_start(byte_offset)
+ end
+ end
+
# This represents a location in the source.
class Location
# A Source object that is used to determine more information from the given
@@ -171,11 +223,25 @@ module Prism
"#<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.
+ def source_lines
+ source.lines
+ end
+
# The source code that this location represents.
def slice
source.slice(start_offset, length)
end
+ # 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.
+ def slice_lines
+ line_start = source.line_start(start_offset)
+ line_end = source.line_end(end_offset)
+ source.slice(line_start, line_end - line_start)
+ end
+
# The character offset from the beginning of the source where this location
# starts.
def start_character_offset
@@ -281,6 +347,18 @@ module Prism
Location.new(source, start_offset, other.end_offset - start_offset)
end
+
+ # 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.
+ def adjoin(string)
+ line_suffix = source.slice(end_offset, source.line_end(end_offset) - end_offset)
+
+ line_suffix_index = line_suffix.byteindex(string)
+ raise "Could not find #{string}" if line_suffix_index.nil?
+
+ Location.new(source, start_offset, length + line_suffix_index + string.bytesize)
+ end
end
# This represents a comment that was encountered during parsing. It is the
@@ -438,14 +516,9 @@ module Prism
end
# This represents the result of a call to ::parse or ::parse_file. It contains
- # the AST, any comments that were encounters, and any errors that were
- # encountered.
- class ParseResult
- # The value that was generated by parsing. Normally this holds the AST, but
- # it can sometimes how a list of tokens or other results passed back from
- # the parser.
- attr_reader :value
-
+ # the 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
@@ -466,9 +539,8 @@ module Prism
# A Source instance that represents the source code that was parsed.
attr_reader :source
- # Create a new parse result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
- @value = value
+ # Create a new result object with the given values.
+ def initialize(comments, magic_comments, data_loc, errors, warnings, source)
@comments = comments
@magic_comments = magic_comments
@data_loc = data_loc
@@ -477,9 +549,9 @@ module Prism
@source = source
end
- # Implement the hash pattern matching interface for ParseResult.
+ # Implement the hash pattern matching interface for Result.
def deconstruct_keys(keys)
- { value: value, comments: comments, magic_comments: magic_comments, data_loc: data_loc, errors: errors, warnings: warnings }
+ { 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.
@@ -500,6 +572,75 @@ module Prism
end
end
+ # This is a result specific to the `parse` and `parse_file` methods.
+ class ParseResult < Result
+ autoload :Comments, "prism/parse_result/comments"
+ autoload :Newlines, "prism/parse_result/newlines"
+
+ private_constant :Comments
+ private_constant :Newlines
+
+ # The syntax tree that was parsed from the source code.
+ attr_reader :value
+
+ # Create a new parse result object with the given values.
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
+ @value = value
+ super(comments, magic_comments, data_loc, errors, warnings, source)
+ end
+
+ # Implement the hash pattern matching interface for ParseResult.
+ def deconstruct_keys(keys)
+ super.merge!(value: value)
+ end
+
+ # Attach the list of comments to their respective locations in the tree.
+ 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.
+ def mark_newlines!
+ value.accept(Newlines.new(source.offsets.size)) # steep:ignore
+ end
+ end
+
+ # 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
+
+ # Create a new lex result object with the given values.
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
+ @value = value
+ super(comments, magic_comments, data_loc, errors, warnings, source)
+ end
+
+ # Implement the hash pattern matching interface for LexResult.
+ def deconstruct_keys(keys)
+ super.merge!(value: value)
+ end
+ end
+
+ # This is a result specific to the `parse_lex` and `parse_lex_file` methods.
+ class ParseLexResult < Result
+ # A tuple of the syntax tree and the list of tokens that were parsed from
+ # the source code.
+ attr_reader :value
+
+ # Create a new parse lex result object with the given values.
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
+ @value = value
+ super(comments, magic_comments, data_loc, errors, warnings, source)
+ end
+
+ # Implement the hash pattern matching interface for ParseLexResult.
+ def deconstruct_keys(keys)
+ super.merge!(value: value)
+ end
+ end
+
# This represents a token from the Ruby source.
class Token
# The Source object that represents the source this token came from.
diff --git a/lib/prism/parse_result/comments.rb b/lib/prism/parse_result/comments.rb
index f8f74d2503..22c4148b2c 100644
--- a/lib/prism/parse_result/comments.rb
+++ b/lib/prism/parse_result/comments.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Prism
- class ParseResult
+ class ParseResult < Result
# When we've parsed the source, we have both the syntax tree and the list of
# comments that we found in the source. This class is responsible for
# walking the tree and finding the nearest location to attach each comment.
@@ -183,12 +183,5 @@ module Prism
[preceding, NodeTarget.new(node), following]
end
end
-
- private_constant :Comments
-
- # Attach the list of comments to their respective locations in the tree.
- def attach_comments!
- Comments.new(self).attach! # steep:ignore
- end
end
end
diff --git a/lib/prism/parse_result/newlines.rb b/lib/prism/parse_result/newlines.rb
index 03acb0b862..cc1343dfda 100644
--- a/lib/prism/parse_result/newlines.rb
+++ b/lib/prism/parse_result/newlines.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Prism
- class ParseResult
+ class ParseResult < Result
# The :line tracepoint event gets fired whenever the Ruby VM encounters an
# expression on a new line. The types of expressions that can trigger this
# event are:
@@ -17,21 +17,26 @@ module Prism
# Note that the logic in this file should be kept in sync with the Java
# MarkNewlinesVisitor, since that visitor is responsible for marking the
# newlines for JRuby/TruffleRuby.
+ #
+ # This file is autoloaded only when `mark_newlines!` is called, so the
+ # re-opening of the various nodes in this file will only be performed in
+ # 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
# Create a new Newlines visitor with the given newline offsets.
- def initialize(newline_marked)
- @newline_marked = newline_marked
+ def initialize(lines)
+ @lines = Array.new(1 + lines, false)
end
# Permit block/lambda nodes to mark newlines within themselves.
def visit_block_node(node)
- old_newline_marked = @newline_marked
- @newline_marked = Array.new(old_newline_marked.size, false)
+ old_lines = @lines
+ @lines = Array.new(old_lines.size, false)
begin
super(node)
ensure
- @newline_marked = old_newline_marked
+ @lines = old_lines
end
end
@@ -39,7 +44,7 @@ module Prism
# Mark if/unless nodes as newlines.
def visit_if_node(node)
- node.set_newline_flag(@newline_marked)
+ node.newline!(@lines)
super(node)
end
@@ -48,19 +53,101 @@ module Prism
# Permit statements lists to mark newlines within themselves.
def visit_statements_node(node)
node.body.each do |child|
- child.set_newline_flag(@newline_marked)
+ child.newline!(@lines)
end
super(node)
end
end
+ end
+
+ class Node
+ def newline? # :nodoc:
+ @newline ? true : false
+ end
+
+ def newline!(lines) # :nodoc:
+ line = location.start_line
+ unless lines[line]
+ lines[line] = true
+ @newline = true
+ end
+ end
+ end
+
+ class BeginNode < Node
+ def newline!(lines) # :nodoc:
+ # Never mark BeginNode with a newline flag, mark children instead.
+ end
+ end
+
+ class ParenthesesNode < Node
+ def newline!(lines) # :nodoc:
+ # Never mark ParenthesesNode with a newline flag, mark children instead.
+ end
+ end
+
+ class IfNode < Node
+ def newline!(lines) # :nodoc:
+ predicate.newline!(lines)
+ end
+ end
+
+ class UnlessNode < Node
+ def newline!(lines) # :nodoc:
+ predicate.newline!(lines)
+ end
+ end
+
+ class UntilNode < Node
+ def newline!(lines) # :nodoc:
+ predicate.newline!(lines)
+ end
+ end
+
+ class WhileNode < Node
+ def newline!(lines) # :nodoc:
+ predicate.newline!(lines)
+ end
+ end
+
+ class RescueModifierNode < Node
+ def newline!(lines) # :nodoc:
+ expression.newline!(lines)
+ end
+ end
+
+ class InterpolatedMatchLastLineNode < Node
+ def newline!(lines) # :nodoc:
+ first = parts.first
+ first.newline!(lines) if first
+ end
+ end
+
+ class InterpolatedRegularExpressionNode < Node
+ def newline!(lines) # :nodoc:
+ first = parts.first
+ first.newline!(lines) if first
+ end
+ end
+
+ class InterpolatedStringNode < Node
+ def newline!(lines) # :nodoc:
+ first = parts.first
+ first.newline!(lines) if first
+ end
+ end
- private_constant :Newlines
+ class InterpolatedSymbolNode < Node
+ def newline!(lines) # :nodoc:
+ first = parts.first
+ first.newline!(lines) if first
+ end
+ end
- # Walk the tree and mark nodes that are on a new line.
- def mark_newlines!
- value = self.value
- raise "This method should only be called on a parse result that contains a node" unless Node === value
- value.accept(Newlines.new(Array.new(1 + source.offsets.size, false))) # steep:ignore
+ class InterpolatedXStringNode < Node
+ def newline!(lines) # :nodoc:
+ first = parts.first
+ first.newline!(lines) if first
end
end
end
diff --git a/lib/prism/pattern.rb b/lib/prism/pattern.rb
index e12cfd597f..03fec26789 100644
--- a/lib/prism/pattern.rb
+++ b/lib/prism/pattern.rb
@@ -149,7 +149,10 @@ module Prism
parent = node.parent
if parent.is_a?(ConstantReadNode) && parent.slice == "Prism"
- compile_node(node.child)
+ name = node.name
+ raise CompilationError, node.inspect if name.nil?
+
+ compile_constant_name(node, name)
else
compile_error(node)
end
@@ -158,14 +161,17 @@ module Prism
# in ConstantReadNode
# in String
def compile_constant_read_node(node)
- value = node.slice
+ compile_constant_name(node, node.name)
+ end
- if Prism.const_defined?(value, false)
- clazz = Prism.const_get(value)
+ # Compile a name associated with a constant.
+ def compile_constant_name(node, name)
+ if Prism.const_defined?(name, false)
+ clazz = Prism.const_get(name)
->(other) { clazz === other }
- elsif Object.const_defined?(value, false)
- clazz = Object.const_get(value)
+ elsif Object.const_defined?(name, false)
+ clazz = Object.const_get(name)
->(other) { clazz === other }
else
diff --git a/lib/prism/polyfill/byteindex.rb b/lib/prism/polyfill/byteindex.rb
new file mode 100644
index 0000000000..98c6089f14
--- /dev/null
+++ b/lib/prism/polyfill/byteindex.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+# Polyfill for String#byteindex, which didn't exist until Ruby 3.2.
+if !("".respond_to?(:byteindex))
+ String.include(
+ Module.new {
+ def byteindex(needle, offset = 0)
+ charindex = index(needle, offset)
+ slice(0...charindex).bytesize if charindex
+ end
+ }
+ )
+end
diff --git a/lib/prism/polyfill/string.rb b/lib/prism/polyfill/string.rb
deleted file mode 100644
index 582266d956..0000000000
--- a/lib/prism/polyfill/string.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-# Polyfill for String#unpack1 with the offset parameter.
-if String.instance_method(:unpack1).parameters.none? { |_, name| name == :offset }
- String.prepend(
- Module.new {
- def unpack1(format, offset: 0) # :nodoc:
- offset == 0 ? super(format) : self[offset..].unpack1(format) # steep:ignore
- end
- }
- )
-end
diff --git a/lib/prism/polyfill/unpack1.rb b/lib/prism/polyfill/unpack1.rb
new file mode 100644
index 0000000000..3fa9b5a0c5
--- /dev/null
+++ b/lib/prism/polyfill/unpack1.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+# Polyfill for String#unpack1 with the offset parameter. Not all Ruby engines
+# have Method#parameters implemented, so we check the arity instead if
+# necessary.
+if (unpack1 = String.instance_method(:unpack1)).respond_to?(:parameters) ? unpack1.parameters.none? { |_, name| name == :offset } : (unpack1.arity == 1)
+ String.prepend(
+ Module.new {
+ def unpack1(format, offset: 0) # :nodoc:
+ offset == 0 ? super(format) : self[offset..].unpack1(format) # steep:ignore
+ end
+ }
+ )
+end
diff --git a/lib/prism/prism.gemspec b/lib/prism/prism.gemspec
index c0f3db5594..374591bb70 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 = "0.25.0"
+ spec.version = "0.29.0"
spec.authors = ["Shopify"]
spec.email = ["ruby@shopify.com"]
@@ -76,17 +76,18 @@ Gem::Specification.new do |spec|
"lib/prism/dot_visitor.rb",
"lib/prism/dsl.rb",
"lib/prism/ffi.rb",
+ "lib/prism/inspect_visitor.rb",
"lib/prism/lex_compat.rb",
"lib/prism/mutation_compiler.rb",
"lib/prism/node_ext.rb",
- "lib/prism/node_inspector.rb",
"lib/prism/node.rb",
"lib/prism/pack.rb",
"lib/prism/parse_result.rb",
"lib/prism/parse_result/comments.rb",
"lib/prism/parse_result/newlines.rb",
"lib/prism/pattern.rb",
- "lib/prism/polyfill/string.rb",
+ "lib/prism/polyfill/byteindex.rb",
+ "lib/prism/polyfill/unpack1.rb",
"lib/prism/reflection.rb",
"lib/prism/serialize.rb",
"lib/prism/translation.rb",
@@ -101,11 +102,42 @@ Gem::Specification.new do |spec|
"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/inspect_visitor.rbi",
+ "rbi/prism/node_ext.rbi",
+ "rbi/prism/node.rbi",
+ "rbi/prism/parse_result.rbi",
+ "rbi/prism/reflection.rbi",
+ "rbi/prism/translation/parser.rbi",
+ "rbi/prism/translation/parser33.rbi",
+ "rbi/prism/translation/parser34.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/pattern.rbs",
+ "sig/prism/reflection.rbs",
+ "sig/prism/serialize.rbs",
+ "sig/prism/visitor.rbs",
"src/diagnostic.c",
"src/encoding.c",
"src/node.c",
+ "src/options.c",
"src/pack.c",
"src/prettyprint.c",
+ "src/prism.c",
"src/regexp.c",
"src/serialize.c",
"src/static_literals.c",
@@ -117,40 +149,10 @@ Gem::Specification.new do |spec|
"src/util/pm_list.c",
"src/util/pm_memchr.c",
"src/util/pm_newline_list.c",
- "src/util/pm_string.c",
"src/util/pm_string_list.c",
+ "src/util/pm_string.c",
"src/util/pm_strncasecmp.c",
- "src/util/pm_strpbrk.c",
- "src/options.c",
- "src/prism.c",
- "prism.gemspec",
- "sig/prism.rbs",
- "sig/prism/compiler.rbs",
- "sig/prism/dispatcher.rbs",
- "sig/prism/dot_visitor.rbs",
- "sig/prism/dsl.rbs",
- "sig/prism/mutation_compiler.rbs",
- "sig/prism/node.rbs",
- "sig/prism/node_ext.rbs",
- "sig/prism/pack.rbs",
- "sig/prism/parse_result.rbs",
- "sig/prism/pattern.rbs",
- "sig/prism/reflection.rbs",
- "sig/prism/serialize.rbs",
- "sig/prism/visitor.rbs",
- "rbi/prism.rbi",
- "rbi/prism/compiler.rbi",
- "rbi/prism/desugar_compiler.rbi",
- "rbi/prism/mutation_compiler.rbi",
- "rbi/prism/node_ext.rbi",
- "rbi/prism/node.rbi",
- "rbi/prism/parse_result.rbi",
- "rbi/prism/reflection.rbi",
- "rbi/prism/translation/parser/compiler.rbi",
- "rbi/prism/translation/ripper.rbi",
- "rbi/prism/translation/ripper/ripper_compiler.rbi",
- "rbi/prism/translation/ruby_parser.rbi",
- "rbi/prism/visitor.rbi"
+ "src/util/pm_strpbrk.c"
]
spec.extensions = ["ext/prism/extconf.rb"]
diff --git a/lib/prism/translation/parser.rb b/lib/prism/translation/parser.rb
index 0d11b8f566..3748fc896e 100644
--- a/lib/prism/translation/parser.rb
+++ b/lib/prism/translation/parser.rb
@@ -1,6 +1,11 @@
# frozen_string_literal: true
-require "parser"
+begin
+ require "parser"
+rescue LoadError
+ warn(%q{Error: Unable to load parser. Add `gem "parser"` to your Gemfile.})
+ exit(1)
+end
module Prism
module Translation
@@ -46,7 +51,7 @@ module Prism
source = source_buffer.source
offset_cache = build_offset_cache(source)
- result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version)), offset_cache)
+ result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version), scopes: [[]]), offset_cache)
build_ast(result.value, offset_cache)
ensure
@@ -59,7 +64,7 @@ module Prism
source = source_buffer.source
offset_cache = build_offset_cache(source)
- result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version)), offset_cache)
+ result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version), scopes: [[]]), offset_cache)
[
build_ast(result.value, offset_cache),
@@ -78,7 +83,7 @@ module Prism
offset_cache = build_offset_cache(source)
result =
begin
- unwrap(Prism.parse_lex(source, filepath: source_buffer.name, version: convert_for_prism(version)), offset_cache)
+ unwrap(Prism.parse_lex(source, filepath: source_buffer.name, version: convert_for_prism(version), scopes: [[]]), offset_cache)
rescue ::Parser::SyntaxError
raise if !recover
end
@@ -149,17 +154,17 @@ module Prism
Diagnostic.new(:error, :endless_setter, {}, diagnostic_location, [])
when :embdoc_term
Diagnostic.new(:error, :embedded_document, {}, diagnostic_location, [])
- when :incomplete_variable_class, :incomplete_variable_class_3_3_0
+ when :incomplete_variable_class, :incomplete_variable_class_3_3
location = location.copy(length: location.length + 1)
diagnostic_location = build_range(location, offset_cache)
Diagnostic.new(:error, :cvar_name, { name: location.slice }, diagnostic_location, [])
- when :incomplete_variable_instance, :incomplete_variable_instance_3_3_0
+ when :incomplete_variable_instance, :incomplete_variable_instance_3_3
location = location.copy(length: location.length + 1)
diagnostic_location = build_range(location, offset_cache)
Diagnostic.new(:error, :ivar_name, { name: location.slice }, diagnostic_location, [])
- when :invalid_variable_global, :invalid_variable_global_3_3_0
+ when :invalid_variable_global, :invalid_variable_global_3_3
Diagnostic.new(:error, :gvar_name, { name: location.slice }, diagnostic_location, [])
when :module_in_method
Diagnostic.new(:error, :module_in_def, {}, diagnostic_location, [])
@@ -284,7 +289,7 @@ module Prism
def convert_for_prism(version)
case version
when 33
- "3.3.0"
+ "3.3.1"
when 34
"3.4.0"
else
diff --git a/lib/prism/translation/parser/compiler.rb b/lib/prism/translation/parser/compiler.rb
index 9437589623..a6c3118efd 100644
--- a/lib/prism/translation/parser/compiler.rb
+++ b/lib/prism/translation/parser/compiler.rb
@@ -328,18 +328,48 @@ module Prism
[],
nil
),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end
# foo.bar &&= baz
# ^^^^^^^^^^^^^^^
- alias visit_call_and_write_node visit_call_operator_write_node
+ def visit_call_and_write_node(node)
+ call_operator_loc = node.call_operator_loc
+
+ builder.op_assign(
+ builder.call_method(
+ visit(node.receiver),
+ call_operator_loc.nil? ? nil : [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)],
+ node.message_loc ? [node.read_name, srange(node.message_loc)] : nil,
+ nil,
+ [],
+ nil
+ ),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# foo.bar ||= baz
# ^^^^^^^^^^^^^^^
- alias visit_call_or_write_node visit_call_operator_write_node
+ def visit_call_or_write_node(node)
+ call_operator_loc = node.call_operator_loc
+
+ builder.op_assign(
+ builder.call_method(
+ visit(node.receiver),
+ call_operator_loc.nil? ? nil : [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)],
+ node.message_loc ? [node.read_name, srange(node.message_loc)] : nil,
+ nil,
+ [],
+ nil
+ ),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# foo.bar, = 1
# ^^^^^^^
@@ -419,18 +449,30 @@ module Prism
def visit_class_variable_operator_write_node(node)
builder.op_assign(
builder.assignable(builder.cvar(token(node.name_loc))),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end
# @@foo &&= bar
# ^^^^^^^^^^^^^
- alias visit_class_variable_and_write_node visit_class_variable_operator_write_node
+ def visit_class_variable_and_write_node(node)
+ builder.op_assign(
+ builder.assignable(builder.cvar(token(node.name_loc))),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# @@foo ||= bar
# ^^^^^^^^^^^^^
- alias visit_class_variable_or_write_node visit_class_variable_operator_write_node
+ def visit_class_variable_or_write_node(node)
+ builder.op_assign(
+ builder.assignable(builder.cvar(token(node.name_loc))),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# @@foo, = bar
# ^^^^^
@@ -458,18 +500,30 @@ module Prism
def visit_constant_operator_write_node(node)
builder.op_assign(
builder.assignable(builder.const([node.name, srange(node.name_loc)])),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end
# Foo &&= bar
# ^^^^^^^^^^^^
- alias visit_constant_and_write_node visit_constant_operator_write_node
+ def visit_constant_and_write_node(node)
+ builder.op_assign(
+ builder.assignable(builder.const([node.name, srange(node.name_loc)])),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# Foo ||= bar
# ^^^^^^^^^^^^
- alias visit_constant_or_write_node visit_constant_operator_write_node
+ def visit_constant_or_write_node(node)
+ builder.op_assign(
+ builder.assignable(builder.const([node.name, srange(node.name_loc)])),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# Foo, = bar
# ^^^
@@ -483,13 +537,13 @@ module Prism
if node.parent.nil?
builder.const_global(
token(node.delimiter_loc),
- [node.child.name, srange(node.child.location)]
+ [node.name, srange(node.name_loc)]
)
else
builder.const_fetch(
visit(node.parent),
token(node.delimiter_loc),
- [node.child.name, srange(node.child.location)]
+ [node.name, srange(node.name_loc)]
)
end
end
@@ -512,18 +566,30 @@ module Prism
def visit_constant_path_operator_write_node(node)
builder.op_assign(
builder.assignable(visit(node.target)),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end
# Foo::Bar &&= baz
# ^^^^^^^^^^^^^^^^
- alias visit_constant_path_and_write_node visit_constant_path_operator_write_node
+ def visit_constant_path_and_write_node(node)
+ builder.op_assign(
+ builder.assignable(visit(node.target)),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# Foo::Bar ||= baz
# ^^^^^^^^^^^^^^^^
- alias visit_constant_path_or_write_node visit_constant_path_operator_write_node
+ def visit_constant_path_or_write_node(node)
+ builder.op_assign(
+ builder.assignable(visit(node.target)),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# Foo::Bar, = baz
# ^^^^^^^^
@@ -711,18 +777,30 @@ module Prism
def visit_global_variable_operator_write_node(node)
builder.op_assign(
builder.assignable(builder.gvar(token(node.name_loc))),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end
# $foo &&= bar
# ^^^^^^^^^^^^
- alias visit_global_variable_and_write_node visit_global_variable_operator_write_node
+ def visit_global_variable_and_write_node(node)
+ builder.op_assign(
+ builder.assignable(builder.gvar(token(node.name_loc))),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# $foo ||= bar
# ^^^^^^^^^^^^
- alias visit_global_variable_or_write_node visit_global_variable_operator_write_node
+ def visit_global_variable_or_write_node(node)
+ builder.op_assign(
+ builder.assignable(builder.gvar(token(node.name_loc))),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# $foo, = bar
# ^^^^
@@ -839,7 +917,7 @@ module Prism
token(node.in_loc),
pattern,
guard,
- srange_find(node.pattern.location.end_offset, node.statements&.location&.start_offset || node.location.end_offset, [";", "then"]),
+ srange_find(node.pattern.location.end_offset, node.statements&.location&.start_offset, [";", "then"]),
visit(node.statements)
)
end
@@ -857,18 +935,46 @@ module Prism
visit_all(arguments),
token(node.closing_loc)
),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end
# foo[bar] &&= baz
# ^^^^^^^^^^^^^^^^
- alias visit_index_and_write_node visit_index_operator_write_node
+ def visit_index_and_write_node(node)
+ arguments = node.arguments&.arguments || []
+ arguments << node.block if node.block
+
+ builder.op_assign(
+ builder.index(
+ visit(node.receiver),
+ token(node.opening_loc),
+ visit_all(arguments),
+ token(node.closing_loc)
+ ),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# foo[bar] ||= baz
# ^^^^^^^^^^^^^^^^
- alias visit_index_or_write_node visit_index_operator_write_node
+ def visit_index_or_write_node(node)
+ arguments = node.arguments&.arguments || []
+ arguments << node.block if node.block
+
+ builder.op_assign(
+ builder.index(
+ visit(node.receiver),
+ token(node.opening_loc),
+ visit_all(arguments),
+ token(node.closing_loc)
+ ),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# foo[bar], = 1
# ^^^^^^^^
@@ -902,18 +1008,30 @@ module Prism
def visit_instance_variable_operator_write_node(node)
builder.op_assign(
builder.assignable(builder.ivar(token(node.name_loc))),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end
# @foo &&= bar
# ^^^^^^^^^^^^
- alias visit_instance_variable_and_write_node visit_instance_variable_operator_write_node
+ def visit_instance_variable_and_write_node(node)
+ builder.op_assign(
+ builder.assignable(builder.ivar(token(node.name_loc))),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# @foo ||= bar
# ^^^^^^^^^^^^
- alias visit_instance_variable_or_write_node visit_instance_variable_operator_write_node
+ def visit_instance_variable_or_write_node(node)
+ builder.op_assign(
+ builder.assignable(builder.ivar(token(node.name_loc))),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# @foo, = bar
# ^^^^
@@ -1030,6 +1148,12 @@ module Prism
end
end
+ # -> { it }
+ # ^^^^^^^^^
+ def visit_it_parameters_node(node)
+ builder.args(nil, [], nil, false)
+ end
+
# foo(bar: baz)
# ^^^^^^^^
def visit_keyword_hash_node(node)
@@ -1052,13 +1176,14 @@ module Prism
# ^^^^^
def visit_lambda_node(node)
parameters = node.parameters
+ implicit_parameters = parameters.is_a?(NumberedParametersNode) || parameters.is_a?(ItParametersNode)
builder.block(
builder.call_lambda(token(node.operator_loc)),
[node.opening, srange(node.opening_loc)],
if parameters.nil?
builder.args(nil, [], nil, false)
- elsif node.parameters.is_a?(NumberedParametersNode)
+ elsif implicit_parameters
visit(node.parameters)
else
builder.args(
@@ -1068,7 +1193,7 @@ module Prism
false
)
end,
- node.body&.accept(copy_compiler(forwarding: parameters.is_a?(NumberedParametersNode) ? [] : find_forwarding(parameters&.parameters))),
+ node.body&.accept(copy_compiler(forwarding: implicit_parameters ? [] : find_forwarding(parameters&.parameters))),
[node.closing, srange(node.closing_loc)]
)
end
@@ -1076,7 +1201,14 @@ module Prism
# foo
# ^^^
def visit_local_variable_read_node(node)
- builder.ident([node.name, srange(node.location)]).updated(:lvar)
+ name = node.name
+
+ # This is just a guess. parser doesn't have support for the implicit
+ # `it` variable yet, so we'll probably have to visit this once it
+ # does.
+ name = :it if name == :"0it"
+
+ builder.ident([name, srange(node.location)]).updated(:lvar)
end
# foo = 1
@@ -1094,18 +1226,30 @@ module Prism
def visit_local_variable_operator_write_node(node)
builder.op_assign(
builder.assignable(builder.ident(token(node.name_loc))),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end
# foo &&= bar
# ^^^^^^^^^^^
- alias visit_local_variable_and_write_node visit_local_variable_operator_write_node
+ def visit_local_variable_and_write_node(node)
+ builder.op_assign(
+ builder.assignable(builder.ident(token(node.name_loc))),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# foo ||= bar
# ^^^^^^^^^^^
- alias visit_local_variable_or_write_node visit_local_variable_operator_write_node
+ def visit_local_variable_or_write_node(node)
+ builder.op_assign(
+ builder.assignable(builder.ident(token(node.name_loc))),
+ [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
+ visit(node.value)
+ )
+ end
# foo, = bar
# ^^^
@@ -1535,19 +1679,29 @@ module Prism
elsif node.opening == "?"
builder.character([node.unescaped, srange(node.location)])
else
- parts = if node.content.lines.count <= 1 || node.unescaped.lines.count <= 1
- [builder.string_internal([node.unescaped, srange(node.content_loc)])]
- else
- start_offset = node.content_loc.start_offset
+ content_lines = node.content.lines
+ unescaped_lines = node.unescaped.lines
- [node.content.lines, node.unescaped.lines].transpose.map do |content_line, unescaped_line|
- end_offset = start_offset + content_line.length
- offsets = srange_offsets(start_offset, end_offset)
- start_offset = end_offset
+ parts =
+ if content_lines.length <= 1 || unescaped_lines.length <= 1
+ [builder.string_internal([node.unescaped, srange(node.content_loc)])]
+ elsif content_lines.length != unescaped_lines.length
+ # This occurs when we have line continuations in the string. We
+ # need to come back and fix this, but for now this stops the
+ # code from breaking when we encounter it because of trying to
+ # transpose arrays of different lengths.
+ [builder.string_internal([node.unescaped, srange(node.content_loc)])]
+ else
+ start_offset = node.content_loc.start_offset
- builder.string_internal([unescaped_line, offsets])
+ [content_lines, unescaped_lines].transpose.map do |content_line, unescaped_line|
+ end_offset = start_offset + content_line.length
+ offsets = srange_offsets(start_offset, end_offset)
+ start_offset = end_offset
+
+ builder.string_internal([unescaped_line, offsets])
+ end
end
- end
builder.string_compose(
token(node.opening_loc),
@@ -1655,7 +1809,7 @@ module Prism
end
# until foo; bar end
- # ^^^^^^^^^^^^^^^^^
+ # ^^^^^^^^^^^^^^^^^^
#
# bar until foo
# ^^^^^^^^^^^^^
@@ -1688,7 +1842,7 @@ module Prism
if node.then_keyword_loc
token(node.then_keyword_loc)
else
- srange_find(node.conditions.last.location.end_offset, node.statements&.location&.start_offset || (node.conditions.last.location.end_offset + 1), [";"])
+ srange_find(node.conditions.last.location.end_offset, node.statements&.location&.start_offset, [";"])
end,
visit(node.statements)
)
@@ -1847,12 +2001,16 @@ module Prism
# Constructs a new source range by finding the given tokens between the
# given start offset and end offset. If the needle is not found, it
- # returns nil.
+ # 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, tokens)
- tokens.find do |token|
- next unless (index = source_buffer.source.byteslice(start_offset...end_offset).index(token))
- offset = start_offset + index
- return [token, Range.new(source_buffer, offset_cache[offset], offset_cache[offset + token.length])]
+ if (match = source_buffer.source.byteslice(start_offset...end_offset).match(/(\s*)(#{tokens.join("|")})/))
+ _, whitespace, token = *match
+ token_offset = start_offset + whitespace.bytesize
+
+ [token, Range.new(source_buffer, offset_cache[token_offset], offset_cache[token_offset + token.bytesize])]
end
end
@@ -1865,13 +2023,14 @@ module Prism
def visit_block(call, block)
if block
parameters = block.parameters
+ implicit_parameters = parameters.is_a?(NumberedParametersNode) || parameters.is_a?(ItParametersNode)
builder.block(
call,
token(block.opening_loc),
if parameters.nil?
builder.args(nil, [], nil, false)
- elsif parameters.is_a?(NumberedParametersNode)
+ elsif implicit_parameters
visit(parameters)
else
builder.args(
@@ -1886,7 +2045,7 @@ module Prism
false
)
end,
- block.body&.accept(copy_compiler(forwarding: parameters.is_a?(NumberedParametersNode) ? [] : find_forwarding(parameters&.parameters))),
+ block.body&.accept(copy_compiler(forwarding: implicit_parameters ? [] : find_forwarding(parameters&.parameters))),
token(block.closing_loc)
)
else
diff --git a/lib/prism/translation/ripper.rb b/lib/prism/translation/ripper.rb
index 3c06f6a40d..68f658565d 100644
--- a/lib/prism/translation/ripper.rb
+++ b/lib/prism/translation/ripper.rb
@@ -19,31 +19,31 @@ module Prism
# The main known difference is that we may omit dispatching some events in
# some cases. This impacts the following events:
#
- # * on_assign_error
- # * 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
+ # - on_assign_error
+ # - 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+.
# +src+ must be a String or an IO or a object with a #gets method.
- def Ripper.parse(src, filename = "(ripper)", lineno = 1)
+ def self.parse(src, filename = "(ripper)", lineno = 1)
new(src, filename, lineno).parse
end
@@ -54,22 +54,22 @@ module Prism
# 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+.
#
- # require 'ripper'
- # require 'pp'
+ # require "ripper"
+ # require "pp"
#
- # pp Ripper.lex("def m(a) nil end")
- # #=> [[[1, 0], :on_kw, "def", FNAME ],
- # [[1, 3], :on_sp, " ", FNAME ],
- # [[1, 4], :on_ident, "m", ENDFN ],
- # [[1, 5], :on_lparen, "(", BEG|LABEL],
- # [[1, 6], :on_ident, "a", ARG ],
- # [[1, 7], :on_rparen, ")", ENDFN ],
- # [[1, 8], :on_sp, " ", BEG ],
- # [[1, 9], :on_kw, "nil", END ],
- # [[1, 12], :on_sp, " ", END ],
- # [[1, 13], :on_kw, "end", END ]]
+ # pp Ripper.lex("def m(a) nil end")
+ # #=> [[[1, 0], :on_kw, "def", FNAME ],
+ # [[1, 3], :on_sp, " ", FNAME ],
+ # [[1, 4], :on_ident, "m", ENDFN ],
+ # [[1, 5], :on_lparen, "(", BEG|LABEL],
+ # [[1, 6], :on_ident, "a", ARG ],
+ # [[1, 7], :on_rparen, ")", ENDFN ],
+ # [[1, 8], :on_sp, " ", BEG ],
+ # [[1, 9], :on_kw, "nil", END ],
+ # [[1, 12], :on_sp, " ", END ],
+ # [[1, 13], :on_kw, "end", END ]]
#
- def Ripper.lex(src, filename = "-", lineno = 1, raise_errors: false)
+ def self.lex(src, filename = "-", lineno = 1, raise_errors: false)
result = Prism.lex_compat(src, filepath: filename, line: lineno)
if result.failure? && raise_errors
@@ -368,17 +368,17 @@ module Prism
# returning +nil+ in such cases. Use the +raise_errors+ keyword
# to raise a SyntaxError for an error in +src+.
#
- # require "ripper"
- # require "pp"
+ # require "ripper"
+ # require "pp"
#
- # pp Ripper.sexp("def m(a) nil end")
- # #=> [:program,
- # [[:def,
- # [:@ident, "m", [1, 4]],
- # [:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil, nil, nil, nil]],
- # [:bodystmt, [[:var_ref, [:@kw, "nil", [1, 9]]]], nil, nil, nil]]]]
+ # pp Ripper.sexp("def m(a) nil end")
+ # #=> [:program,
+ # [[:def,
+ # [:@ident, "m", [1, 4]],
+ # [:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil, nil, nil, nil]],
+ # [:bodystmt, [[:var_ref, [:@kw, "nil", [1, 9]]]], nil, nil, nil]]]]
#
- def Ripper.sexp(src, filename = "-", lineno = 1, raise_errors: false)
+ def self.sexp(src, filename = "-", lineno = 1, raise_errors: false)
builder = SexpBuilderPP.new(src, filename, lineno)
sexp = builder.parse
if builder.error?
@@ -397,23 +397,23 @@ module Prism
# returning +nil+ in such cases. Use the +raise_errors+ keyword
# to raise a SyntaxError for an error in +src+.
#
- # require 'ripper'
- # require 'pp'
+ # require "ripper"
+ # require "pp"
#
- # pp Ripper.sexp_raw("def m(a) nil end")
- # #=> [:program,
- # [:stmts_add,
- # [:stmts_new],
- # [:def,
- # [:@ident, "m", [1, 4]],
- # [:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil]],
- # [:bodystmt,
- # [:stmts_add, [:stmts_new], [:var_ref, [:@kw, "nil", [1, 9]]]],
- # nil,
- # nil,
- # nil]]]]
+ # pp Ripper.sexp_raw("def m(a) nil end")
+ # #=> [:program,
+ # [:stmts_add,
+ # [:stmts_new],
+ # [:def,
+ # [:@ident, "m", [1, 4]],
+ # [:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil]],
+ # [:bodystmt,
+ # [:stmts_add, [:stmts_new], [:var_ref, [:@kw, "nil", [1, 9]]]],
+ # nil,
+ # nil,
+ # nil]]]]
#
- def Ripper.sexp_raw(src, filename = "-", lineno = 1, raise_errors: false)
+ def self.sexp_raw(src, filename = "-", lineno = 1, raise_errors: false)
builder = SexpBuilder.new(src, filename, lineno)
sexp = builder.parse
if builder.error?
@@ -1181,8 +1181,8 @@ module Prism
bounds(node.location)
target = on_field(receiver, call_operator, message)
- bounds(node.operator_loc)
- operator = on_op("#{node.operator}=")
+ bounds(node.binary_operator_loc)
+ operator = on_op("#{node.binary_operator}=")
value = visit_write_value(node.value)
bounds(node.location)
@@ -1339,8 +1339,8 @@ module Prism
bounds(node.name_loc)
target = on_var_field(on_cvar(node.name.to_s))
- bounds(node.operator_loc)
- operator = on_op("#{node.operator}=")
+ bounds(node.binary_operator_loc)
+ operator = on_op("#{node.binary_operator}=")
value = visit_write_value(node.value)
bounds(node.location)
@@ -1409,8 +1409,8 @@ module Prism
bounds(node.name_loc)
target = on_var_field(on_const(node.name.to_s))
- bounds(node.operator_loc)
- operator = on_op("#{node.operator}=")
+ bounds(node.binary_operator_loc)
+ operator = on_op("#{node.binary_operator}=")
value = visit_write_value(node.value)
bounds(node.location)
@@ -1456,16 +1456,16 @@ module Prism
# ^^^^^^^^
def visit_constant_path_node(node)
if node.parent.nil?
- bounds(node.child.location)
- child = on_const(node.child.name.to_s)
+ bounds(node.name_loc)
+ child = on_const(node.name.to_s)
bounds(node.location)
on_top_const_ref(child)
else
parent = visit(node.parent)
- bounds(node.child.location)
- child = on_const(node.child.name.to_s)
+ bounds(node.name_loc)
+ child = on_const(node.name.to_s)
bounds(node.location)
on_const_path_ref(parent, child)
@@ -1488,16 +1488,16 @@ 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?
- bounds(node.child.location)
- child = on_const(node.child.name.to_s)
+ bounds(node.name_loc)
+ child = on_const(node.name.to_s)
bounds(node.location)
on_top_const_field(child)
else
parent = visit(node.parent)
- bounds(node.child.location)
- child = on_const(node.child.name.to_s)
+ bounds(node.name_loc)
+ child = on_const(node.name.to_s)
bounds(node.location)
on_const_path_field(parent, child)
@@ -1510,8 +1510,8 @@ module Prism
target = visit_constant_path_write_node_target(node.target)
value = visit(node.value)
- bounds(node.operator_loc)
- operator = on_op("#{node.operator}=")
+ bounds(node.binary_operator_loc)
+ operator = on_op("#{node.binary_operator}=")
value = visit_write_value(node.value)
bounds(node.location)
@@ -1802,8 +1802,8 @@ module Prism
bounds(node.name_loc)
target = on_var_field(on_gvar(node.name.to_s))
- bounds(node.operator_loc)
- operator = on_op("#{node.operator}=")
+ bounds(node.binary_operator_loc)
+ operator = on_op("#{node.binary_operator}=")
value = visit_write_value(node.value)
bounds(node.location)
@@ -1983,8 +1983,8 @@ module Prism
bounds(node.location)
target = on_aref_field(receiver, arguments)
- bounds(node.operator_loc)
- operator = on_op("#{node.operator}=")
+ bounds(node.binary_operator_loc)
+ operator = on_op("#{node.binary_operator}=")
value = visit_write_value(node.value)
bounds(node.location)
@@ -2059,8 +2059,8 @@ module Prism
bounds(node.name_loc)
target = on_var_field(on_ivar(node.name.to_s))
- bounds(node.operator_loc)
- operator = on_op("#{node.operator}=")
+ bounds(node.binary_operator_loc)
+ operator = on_op("#{node.binary_operator}=")
value = visit_write_value(node.value)
bounds(node.location)
@@ -2337,8 +2337,8 @@ module Prism
bounds(node.name_loc)
target = on_var_field(on_ident(node.name_loc.slice))
- bounds(node.operator_loc)
- operator = on_op("#{node.operator}=")
+ bounds(node.binary_operator_loc)
+ operator = on_op("#{node.binary_operator}=")
value = visit_write_value(node.value)
bounds(node.location)
@@ -3267,7 +3267,11 @@ module Prism
# Lazily initialize the parse result.
def result
- @result ||= Prism.parse(source)
+ @result ||=
+ begin
+ scopes = RUBY_VERSION >= "3.3.0" ? [] : [[]]
+ Prism.parse(source, scopes: scopes)
+ end
end
##########################################################################
diff --git a/lib/prism/translation/ruby_parser.rb b/lib/prism/translation/ruby_parser.rb
index 5c59fe3181..43aac23be7 100644
--- a/lib/prism/translation/ruby_parser.rb
+++ b/lib/prism/translation/ruby_parser.rb
@@ -1,6 +1,11 @@
# frozen_string_literal: true
-require "ruby_parser"
+begin
+ require "ruby_parser"
+rescue LoadError
+ warn(%q{Error: Unable to load ruby_parser. Add `gem "ruby_parser"` to your Gemfile.})
+ exit(1)
+end
module Prism
module Translation
@@ -271,9 +276,9 @@ module Prism
# ^^^^^^^^^^^^^^^
def visit_call_operator_write_node(node)
if op_asgn?(node)
- s(node, op_asgn_type(node, :op_asgn), visit(node.receiver), visit_write_value(node.value), node.read_name, node.operator)
+ s(node, op_asgn_type(node, :op_asgn), visit(node.receiver), visit_write_value(node.value), node.read_name, node.binary_operator)
else
- s(node, op_asgn_type(node, :op_asgn2), visit(node.receiver), node.write_name, node.operator, visit_write_value(node.value))
+ s(node, op_asgn_type(node, :op_asgn2), visit(node.receiver), node.write_name, node.binary_operator, visit_write_value(node.value))
end
end
@@ -372,7 +377,7 @@ module Prism
# @@foo += bar
# ^^^^^^^^^^^^
def visit_class_variable_operator_write_node(node)
- s(node, class_variable_write_type, node.name, s(node, :call, s(node, :cvar, node.name), node.operator, visit_write_value(node.value)))
+ s(node, class_variable_write_type, node.name, s(node, :call, s(node, :cvar, node.name), node.binary_operator, visit_write_value(node.value)))
end
# @@foo &&= bar
@@ -417,7 +422,7 @@ module Prism
# Foo += bar
# ^^^^^^^^^^^
def visit_constant_operator_write_node(node)
- s(node, :cdecl, node.name, s(node, :call, s(node, :const, node.name), node.operator, visit_write_value(node.value)))
+ s(node, :cdecl, node.name, s(node, :call, s(node, :const, node.name), node.binary_operator, visit_write_value(node.value)))
end
# Foo &&= bar
@@ -442,9 +447,9 @@ module Prism
# ^^^^^^^^
def visit_constant_path_node(node)
if node.parent.nil?
- s(node, :colon3, node.child.name)
+ s(node, :colon3, node.name)
else
- s(node, :colon2, visit(node.parent), node.child.name)
+ s(node, :colon2, visit(node.parent), node.name)
end
end
@@ -460,7 +465,7 @@ module Prism
# Foo::Bar += baz
# ^^^^^^^^^^^^^^^
def visit_constant_path_operator_write_node(node)
- s(node, :op_asgn, visit(node.target), node.operator, visit_write_value(node.value))
+ s(node, :op_asgn, visit(node.target), node.binary_operator, visit_write_value(node.value))
end
# Foo::Bar &&= baz
@@ -627,7 +632,7 @@ module Prism
# $foo += bar
# ^^^^^^^^^^^
def visit_global_variable_operator_write_node(node)
- s(node, :gasgn, node.name, s(node, :call, s(node, :gvar, node.name), node.operator, visit(node.value)))
+ s(node, :gasgn, node.name, s(node, :call, s(node, :gvar, node.name), node.binary_operator, visit(node.value)))
end
# $foo &&= bar
@@ -719,7 +724,7 @@ module Prism
arglist << visit(node.block) if !node.block.nil?
end
- s(node, :op_asgn1, visit(node.receiver), arglist, node.operator, visit_write_value(node.value))
+ s(node, :op_asgn1, visit(node.receiver), arglist, node.binary_operator, visit_write_value(node.value))
end
# foo[bar] &&= baz
@@ -775,7 +780,7 @@ module Prism
# @foo += bar
# ^^^^^^^^^^^
def visit_instance_variable_operator_write_node(node)
- s(node, :iasgn, node.name, s(node, :call, s(node, :ivar, node.name), node.operator, visit_write_value(node.value)))
+ s(node, :iasgn, node.name, s(node, :call, s(node, :ivar, node.name), node.binary_operator, visit_write_value(node.value)))
end
# @foo &&= bar
@@ -805,17 +810,29 @@ module Prism
# if /foo #{bar}/ then end
# ^^^^^^^^^^^^
def visit_interpolated_match_last_line_node(node)
- s(node, :match, s(node, :dregx).concat(visit_interpolated_parts(node.parts)))
+ parts = visit_interpolated_parts(node.parts)
+ regexp =
+ if parts.length == 1
+ s(node, :lit, Regexp.new(parts.first, node.options))
+ else
+ s(node, :dregx).concat(parts).tap do |result|
+ options = node.options
+ result << options if options != 0
+ end
+ end
+
+ s(node, :match, regexp)
end
# /foo #{bar}/
# ^^^^^^^^^^^^
def visit_interpolated_regular_expression_node(node)
- if node.parts.all? { |part| part.is_a?(StringNode) || (part.is_a?(EmbeddedStatementsNode) && part.statements&.body&.length == 1 && part.statements.body.first.is_a?(StringNode)) }
- unescaped = node.parts.map { |part| part.is_a?(StringNode) ? part.unescaped : part.statements.body.first.unescaped }.join
- s(node, :lit, Regexp.new(unescaped, node.options))
+ parts = visit_interpolated_parts(node.parts)
+
+ if parts.length == 1
+ s(node, :lit, Regexp.new(parts.first, node.options))
else
- s(node, :dregx).concat(visit_interpolated_parts(node.parts)).tap do |result|
+ s(node, :dregx).concat(parts).tap do |result|
options = node.options
result << options if options != 0
end
@@ -825,45 +842,71 @@ module Prism
# "foo #{bar}"
# ^^^^^^^^^^^^
def visit_interpolated_string_node(node)
- if (node.parts.all? { |part| part.is_a?(StringNode) || (part.is_a?(EmbeddedStatementsNode) && part.statements&.body&.length == 1 && part.statements.body.first.is_a?(StringNode)) }) ||
- (node.opening.nil? && node.parts.all? { |part| part.is_a?(StringNode) && !part.opening_loc.nil? })
- unescaped = node.parts.map { |part| part.is_a?(StringNode) ? part.unescaped : part.statements.body.first.unescaped }.join
- s(node, :str, unescaped)
- else
- s(node, :dstr).concat(visit_interpolated_parts(node.parts))
- end
+ parts = visit_interpolated_parts(node.parts)
+ parts.length == 1 ? s(node, :str, parts.first) : s(node, :dstr).concat(parts)
end
# :"foo #{bar}"
# ^^^^^^^^^^^^^
def visit_interpolated_symbol_node(node)
- if node.parts.all? { |part| part.is_a?(StringNode) || (part.is_a?(EmbeddedStatementsNode) && part.statements&.body&.length == 1 && part.statements.body.first.is_a?(StringNode)) }
- unescaped = node.parts.map { |part| part.is_a?(StringNode) ? part.unescaped : part.statements.body.first.unescaped }.join
- s(node, :lit, unescaped.to_sym)
- else
- s(node, :dsym).concat(visit_interpolated_parts(node.parts))
- end
+ parts = visit_interpolated_parts(node.parts)
+ parts.length == 1 ? s(node, :lit, parts.first.to_sym) : s(node, :dsym).concat(parts)
end
# `foo #{bar}`
# ^^^^^^^^^^^^
def visit_interpolated_x_string_node(node)
- children = visit_interpolated_parts(node.parts)
- s(node.heredoc? ? node.parts.first : node, :dxstr).concat(children)
+ source = node.heredoc? ? node.parts.first : node
+ parts = visit_interpolated_parts(node.parts)
+ parts.length == 1 ? s(source, :xstr, parts.first) : s(source, :dxstr).concat(parts)
end
# Visit the interpolated content of the string-like node.
private def visit_interpolated_parts(parts)
- parts.each_with_object([]).with_index do |(part, results), index|
- if index == 0
- if part.is_a?(StringNode)
- results << part.unescaped
+ visited = []
+ parts.each do |part|
+ result = visit(part)
+
+ if result[0] == :evstr && result[1]
+ if result[1][0] == :str
+ visited << result[1]
+ elsif result[1][0] == :dstr
+ visited.concat(result[1][1..-1])
+ else
+ visited << result
+ end
+ else
+ visited << result
+ end
+ end
+
+ state = :beginning #: :beginning | :string_content | :interpolated_content
+
+ visited.each_with_object([]) do |result, results|
+ case state
+ when :beginning
+ if result.is_a?(String)
+ results << result
+ state = :string_content
+ elsif result.is_a?(Array) && result[0] == :str
+ results << result[1]
+ state = :string_content
else
results << ""
- results << visit(part)
+ results << result
+ state = :interpolated_content
+ end
+ when :string_content
+ if result.is_a?(String)
+ results[0] << result
+ elsif result.is_a?(Array) && result[0] == :str
+ results[0] << result[1]
+ else
+ results << result
+ state = :interpolated_content
end
else
- results << visit(part)
+ results << result
end
end
end
@@ -922,7 +965,7 @@ module Prism
# foo += bar
# ^^^^^^^^^^
def visit_local_variable_operator_write_node(node)
- s(node, :lasgn, node.name, s(node, :call, s(node, :lvar, node.name), node.operator, visit_write_value(node.value)))
+ s(node, :lasgn, node.name, s(node, :call, s(node, :lvar, node.name), node.binary_operator, visit_write_value(node.value)))
end
# foo &&= bar
@@ -1297,7 +1340,7 @@ module Prism
# __FILE__
# ^^^^^^^^
def visit_source_file_node(node)
- s(node, :str, file)
+ s(node, :str, node.filepath)
end
# __LINE__
@@ -1498,13 +1541,13 @@ module Prism
# Parse the given source and translate it into the seattlerb/ruby_parser
# gem's Sexp format.
def parse(source, filepath = "(string)")
- translate(Prism.parse(source), filepath)
+ translate(Prism.parse(source, filepath: filepath, scopes: [[]]), filepath)
end
# Parse the given file and translate it into the seattlerb/ruby_parser
# gem's Sexp format.
def parse_file(filepath)
- translate(Prism.parse_file(filepath), filepath)
+ translate(Prism.parse_file(filepath, scopes: [[]]), filepath)
end
class << self
diff --git a/lib/reline.rb b/lib/reline.rb
index f0060f5c9c..fb00b96531 100644
--- a/lib/reline.rb
+++ b/lib/reline.rb
@@ -225,17 +225,20 @@ module Reline
journey_data = completion_journey_data
return unless journey_data
- target = journey_data.list[journey_data.pointer]
+ target = journey_data.list.first
+ completed = journey_data.list[journey_data.pointer]
result = journey_data.list.drop(1)
pointer = journey_data.pointer - 1
- return if target.empty? || (result == [target] && pointer < 0)
+ return if completed.empty? || (result == [completed] && pointer < 0)
target_width = Reline::Unicode.calculate_width(target)
- x = cursor_pos.x - target_width
- if x < 0
- x = screen_width + x
+ completed_width = Reline::Unicode.calculate_width(completed)
+ if cursor_pos.x <= completed_width - target_width
+ # When target is rendered on the line above cursor position
+ x = screen_width - completed_width
y = -1
else
+ x = [cursor_pos.x - completed_width, 0].max
y = 0
end
cursor_pos_to_render = Reline::CursorPos.new(x, y)
@@ -309,6 +312,10 @@ module Reline
$stderr.sync = true
$stderr.puts "Reline is used by #{Process.pid}"
end
+ unless config.test_mode or config.loaded?
+ config.read
+ io_gate.set_default_key_bindings(config)
+ end
otio = io_gate.prep
may_req_ambiguous_char_width
@@ -335,12 +342,6 @@ module Reline
end
end
- unless config.test_mode
- config.read
- config.reset_default_key_bindings
- io_gate.set_default_key_bindings(config)
- end
-
line_editor.print_nomultiline_prompt(prompt)
line_editor.update_dialogs
line_editor.rerender
@@ -350,7 +351,15 @@ module Reline
loop do
read_io(config.keyseq_timeout) { |inputs|
line_editor.set_pasting_state(io_gate.in_pasting?)
- inputs.each { |key| line_editor.update(key) }
+ inputs.each do |key|
+ if key.char == :bracketed_paste_start
+ text = io_gate.read_bracketed_paste
+ line_editor.insert_pasted_text(text)
+ line_editor.scroll_into_view
+ else
+ line_editor.update(key)
+ end
+ end
}
if line_editor.finished?
line_editor.render_finished
diff --git a/lib/reline/ansi.rb b/lib/reline/ansi.rb
index a3719f502c..45a475a787 100644
--- a/lib/reline/ansi.rb
+++ b/lib/reline/ansi.rb
@@ -45,6 +45,7 @@ class Reline::ANSI
end
def self.set_default_key_bindings(config, allow_terminfo: true)
+ set_bracketed_paste_key_bindings(config)
set_default_key_bindings_ansi_cursor(config)
if allow_terminfo && Reline::Terminfo.enabled?
set_default_key_bindings_terminfo(config)
@@ -66,6 +67,12 @@ class Reline::ANSI
end
end
+ def self.set_bracketed_paste_key_bindings(config)
+ [:emacs, :vi_insert, :vi_command].each do |keymap|
+ config.add_default_key_binding_by_keymap(keymap, START_BRACKETED_PASTE.bytes, :bracketed_paste_start)
+ end
+ end
+
def self.set_default_key_bindings_ansi_cursor(config)
ANSI_CURSOR_KEY_BINDINGS.each do |char, (default_func, modifiers)|
bindings = [["\e[#{char}", default_func]] # CSI + char
@@ -178,46 +185,26 @@ class Reline::ANSI
nil
end
- @@in_bracketed_paste_mode = false
- START_BRACKETED_PASTE = String.new("\e[200~,", encoding: Encoding::ASCII_8BIT)
- END_BRACKETED_PASTE = String.new("\e[200~.", encoding: Encoding::ASCII_8BIT)
- def self.getc_with_bracketed_paste(timeout_second)
+ START_BRACKETED_PASTE = String.new("\e[200~", encoding: Encoding::ASCII_8BIT)
+ END_BRACKETED_PASTE = String.new("\e[201~", encoding: Encoding::ASCII_8BIT)
+ def self.read_bracketed_paste
buffer = String.new(encoding: Encoding::ASCII_8BIT)
- buffer << inner_getc(timeout_second)
- while START_BRACKETED_PASTE.start_with?(buffer) or END_BRACKETED_PASTE.start_with?(buffer) do
- if START_BRACKETED_PASTE == buffer
- @@in_bracketed_paste_mode = true
- return inner_getc(timeout_second)
- elsif END_BRACKETED_PASTE == buffer
- @@in_bracketed_paste_mode = false
- ungetc(-1)
- return inner_getc(timeout_second)
- end
- succ_c = inner_getc(Reline.core.config.keyseq_timeout)
-
- if succ_c
- buffer << succ_c
- else
- break
- end
+ until buffer.end_with?(END_BRACKETED_PASTE)
+ c = inner_getc(Float::INFINITY)
+ break unless c
+ buffer << c
end
- buffer.bytes.reverse_each do |ch|
- ungetc ch
- end
- inner_getc(timeout_second)
+ string = buffer.delete_suffix(END_BRACKETED_PASTE).force_encoding(encoding)
+ string.valid_encoding? ? string : ''
end
# if the usage expects to wait indefinitely, use Float::INFINITY for timeout_second
def self.getc(timeout_second)
- if Reline.core.config.enable_bracketed_paste
- getc_with_bracketed_paste(timeout_second)
- else
- inner_getc(timeout_second)
- end
+ inner_getc(timeout_second)
end
def self.in_pasting?
- @@in_bracketed_paste_mode or (not empty_buffer?)
+ not empty_buffer?
end
def self.empty_buffer?
@@ -284,7 +271,7 @@ class Reline::ANSI
buf = @@output.pread(@@output.pos, 0)
row = buf.count("\n")
column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
- rescue Errno::ESPIPE
+ rescue Errno::ESPIPE, IOError
# Just returns column 1 for ambiguous width because this I/O is not
# tty and can't seek.
row = 0
@@ -361,11 +348,15 @@ class Reline::ANSI
end
def self.prep
+ # Enable bracketed paste
+ @@output.write "\e[?2004h" if Reline.core.config.enable_bracketed_paste
retrieve_keybuffer
nil
end
def self.deprep(otio)
+ # Disable bracketed paste
+ @@output.write "\e[?2004l" if Reline.core.config.enable_bracketed_paste
Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
end
end
diff --git a/lib/reline/config.rb b/lib/reline/config.rb
index 4c07a73701..d44c2675ab 100644
--- a/lib/reline/config.rb
+++ b/lib/reline/config.rb
@@ -8,31 +8,12 @@ class Reline::Config
end
VARIABLE_NAMES = %w{
- bind-tty-special-chars
- blink-matching-paren
- byte-oriented
completion-ignore-case
convert-meta
disable-completion
- enable-keypad
- expand-tilde
- history-preserve-point
history-size
- horizontal-scroll-mode
- input-meta
keyseq-timeout
- mark-directories
- mark-modified-lines
- mark-symlinked-directories
- match-hidden-files
- meta-flag
- output-meta
- page-completions
- prefer-visible-bell
- print-completions-horizontally
show-all-if-ambiguous
- show-all-if-unmodified
- visible-stats
show-mode-in-prompt
vi-cmd-mode-string
vi-ins-mode-string
@@ -53,8 +34,6 @@ class Reline::Config
@additional_key_bindings[:vi_insert] = {}
@additional_key_bindings[:vi_command] = {}
@oneshot_key_bindings = {}
- @skip_section = nil
- @if_stack = nil
@editing_mode_label = :emacs
@keymap_label = :emacs
@keymap_prefix = []
@@ -71,17 +50,15 @@ class Reline::Config
@test_mode = false
@autocompletion = false
@convert_meta = true if seven_bit_encoding?(Reline::IOGate.encoding)
+ @loaded = false
+ @enable_bracketed_paste = true
end
def reset
if editing_mode_is?(:vi_command)
@editing_mode_label = :vi_insert
end
- @additional_key_bindings.keys.each do |key|
- @additional_key_bindings[key].clear
- end
@oneshot_key_bindings.clear
- reset_default_key_bindings
end
def editing_mode
@@ -100,6 +77,10 @@ class Reline::Config
@key_actors[@keymap_label]
end
+ def loaded?
+ @loaded
+ end
+
def inputrc_path
case ENV['INPUTRC']
when nil, ''
@@ -131,6 +112,7 @@ class Reline::Config
end
def read(file = nil)
+ @loaded = true
file ||= default_inputrc_path
begin
if file.respond_to?(:readlines)
@@ -173,12 +155,6 @@ class Reline::Config
@key_actors[@keymap_label].default_key_bindings[keystroke] = target
end
- def reset_default_key_bindings
- @key_actors.values.each do |ka|
- ka.reset_default_key_bindings
- end
- end
-
def read_lines(lines, file = nil)
if not lines.empty? and lines.first.encoding != Reline.encoding_system_needs
begin
@@ -190,9 +166,7 @@ class Reline::Config
end
end
end
- conditions = [@skip_section, @if_stack]
- @skip_section = nil
- @if_stack = []
+ if_stack = []
lines.each_with_index do |line, no|
next if line.match(/\A\s*#/)
@@ -201,11 +175,11 @@ class Reline::Config
line = line.chomp.lstrip
if line.start_with?('$')
- handle_directive(line[1..-1], file, no)
+ handle_directive(line[1..-1], file, no, if_stack)
next
end
- next if @skip_section
+ next if if_stack.any? { |_no, skip| skip }
case line
when /^set +([^ ]+) +([^ ]+)/i
@@ -214,43 +188,47 @@ class Reline::Config
next
when /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
key, func_name = $1, $2
+ func_name = func_name.split.first
keystroke, func = bind_key(key, func_name)
next unless keystroke
@additional_key_bindings[@keymap_label][@keymap_prefix + keystroke] = func
end
end
- unless @if_stack.empty?
- raise InvalidInputrc, "#{file}:#{@if_stack.last[1]}: unclosed if"
+ unless if_stack.empty?
+ raise InvalidInputrc, "#{file}:#{if_stack.last[0]}: unclosed if"
end
- ensure
- @skip_section, @if_stack = conditions
end
- def handle_directive(directive, file, no)
+ def handle_directive(directive, file, no, if_stack)
directive, args = directive.split(' ')
case directive
when 'if'
condition = false
case args
- when 'mode'
+ when /^mode=(vi|emacs)$/i
+ mode = $1.downcase
+ # NOTE: mode=vi means vi-insert mode
+ mode = 'vi_insert' if mode == 'vi'
+ if @editing_mode_label == mode.to_sym
+ condition = true
+ end
when 'term'
when 'version'
else # application name
condition = true if args == 'Ruby'
condition = true if args == 'Reline'
end
- @if_stack << [file, no, @skip_section]
- @skip_section = !condition
+ if_stack << [no, !condition]
when 'else'
- if @if_stack.empty?
+ if if_stack.empty?
raise InvalidInputrc, "#{file}:#{no}: unmatched else"
end
- @skip_section = !@skip_section
+ if_stack.last[1] = !if_stack.last[1]
when 'endif'
- if @if_stack.empty?
+ if if_stack.empty?
raise InvalidInputrc, "#{file}:#{no}: unmatched endif"
end
- @skip_section = @if_stack.pop
+ if_stack.pop
when 'include'
read(File.expand_path(args))
end
diff --git a/lib/reline/key_actor/base.rb b/lib/reline/key_actor/base.rb
index a1cd7fb2a1..194e98938c 100644
--- a/lib/reline/key_actor/base.rb
+++ b/lib/reline/key_actor/base.rb
@@ -12,8 +12,4 @@ class Reline::KeyActor::Base
def default_key_bindings
@default_key_bindings
end
-
- def reset_default_key_bindings
- @default_key_bindings.clear
- end
end
diff --git a/lib/reline/key_actor/emacs.rb b/lib/reline/key_actor/emacs.rb
index 5d0a7fb63d..edd88289a3 100644
--- a/lib/reline/key_actor/emacs.rb
+++ b/lib/reline/key_actor/emacs.rb
@@ -19,7 +19,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
# 8 ^H
:em_delete_prev_char,
# 9 ^I
- :ed_unassigned,
+ :complete,
# 10 ^J
:ed_newline,
# 11 ^K
@@ -63,7 +63,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
# 30 ^^
:ed_unassigned,
# 31 ^_
- :ed_unassigned,
+ :undo,
# 32 SPACE
:ed_insert,
# 33 !
diff --git a/lib/reline/key_actor/vi_insert.rb b/lib/reline/key_actor/vi_insert.rb
index c3d7f9c12d..f8ccf468c6 100644
--- a/lib/reline/key_actor/vi_insert.rb
+++ b/lib/reline/key_actor/vi_insert.rb
@@ -19,7 +19,7 @@ class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
# 8 ^H
:vi_delete_prev_char,
# 9 ^I
- :ed_insert,
+ :complete,
# 10 ^J
:ed_newline,
# 11 ^K
@@ -29,11 +29,11 @@ class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
# 13 ^M
:ed_newline,
# 14 ^N
- :ed_insert,
+ :menu_complete,
# 15 ^O
:ed_insert,
# 16 ^P
- :ed_insert,
+ :menu_complete_backward,
# 17 ^Q
:ed_ignore,
# 18 ^R
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index 6e5ef11bc0..23ece60220 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -4,7 +4,6 @@ require 'reline/unicode'
require 'tempfile'
class Reline::LineEditor
- # TODO: undo
# TODO: Use "private alias_method" idiom after drop Ruby 2.5.
attr_reader :byte_pointer
attr_accessor :confirm_multiline_termination_proc
@@ -75,7 +74,7 @@ class Reline::LineEditor
def initialize(config, encoding)
@config = config
@completion_append_character = ''
- @screen_size = Reline::IOGate.get_screen_size
+ @screen_size = [0, 0] # Should be initialized with actual winsize in LineEditor#reset
reset_variables(encoding: encoding)
end
@@ -235,7 +234,6 @@ class Reline::LineEditor
@vi_waiting_operator_arg = nil
@completion_journey_state = nil
@completion_state = CompletionState::NORMAL
- @completion_occurs = false
@perfect_matched = nil
@menu_info = nil
@searching_prompt = nil
@@ -252,6 +250,8 @@ class Reline::LineEditor
@resized = false
@cache = {}
@rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0)
+ @past_lines = []
+ @undoing = false
reset_line
end
@@ -284,7 +284,7 @@ class Reline::LineEditor
indent1 = @auto_indent_proc.(@buffer_of_lines.take(@line_index - 1).push(''), @line_index - 1, 0, true)
indent2 = @auto_indent_proc.(@buffer_of_lines.take(@line_index), @line_index - 1, @buffer_of_lines[@line_index - 1].bytesize, false)
indent = indent2 || indent1
- @buffer_of_lines[@line_index - 1] = ' ' * indent + @buffer_of_lines[@line_index - 1].gsub(/\A */, '')
+ @buffer_of_lines[@line_index - 1] = ' ' * indent + @buffer_of_lines[@line_index - 1].gsub(/\A\s*/, '')
)
process_auto_indent @line_index, add_newline: true
else
@@ -295,8 +295,8 @@ class Reline::LineEditor
end
end
- private def split_by_width(str, max_width)
- Reline::Unicode.split_by_width(str, max_width, @encoding)
+ private def split_by_width(str, max_width, offset: 0)
+ Reline::Unicode.split_by_width(str, max_width, @encoding, offset: offset)
end
def current_byte_pointer_cursor
@@ -370,7 +370,7 @@ class Reline::LineEditor
@scroll_partial_screen
end
- def wrapped_lines
+ def wrapped_prompt_and_input_lines
with_cache(__method__, @buffer_of_lines.size, modified_lines, prompt_list, screen_width) do |n, lines, prompts, width, prev_cache_key, cached_value|
prev_n, prev_lines, prev_prompts, prev_width = prev_cache_key
cached_wraps = {}
@@ -381,9 +381,14 @@ class Reline::LineEditor
end
n.times.map do |i|
- prompt = prompts[i]
- line = lines[i]
- cached_wraps[[prompt, line]] || split_by_width("#{prompt}#{line}", width).first.compact
+ prompt = prompts[i] || ''
+ line = lines[i] || ''
+ if (cached = cached_wraps[[prompt, line]])
+ next cached
+ end
+ *wrapped_prompts, code_line_prompt = split_by_width(prompt, width).first.compact
+ wrapped_lines = split_by_width(line, width, offset: calculate_width(code_line_prompt, true)).first.compact
+ wrapped_prompts.map { |p| [p, ''] } + [[code_line_prompt, wrapped_lines.first]] + wrapped_lines.drop(1).map { |c| ['', c] }
end
end
end
@@ -409,8 +414,13 @@ class Reline::LineEditor
@output.write "#{Reline::IOGate::RESET_COLOR}#{' ' * width}"
else
x, w, content = new_items[level]
- content = Reline::Unicode.take_range(content, base_x - x, width) unless x == base_x && w == width
- Reline::IOGate.move_cursor_column base_x
+ cover_begin = base_x != 0 && new_levels[base_x - 1] == level
+ cover_end = new_levels[base_x + width] == level
+ pos = 0
+ unless x == base_x && w == width
+ content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
+ end
+ Reline::IOGate.move_cursor_column x + pos
@output.write "#{Reline::IOGate::RESET_COLOR}#{content}#{Reline::IOGate::RESET_COLOR}"
end
base_x += width
@@ -426,7 +436,7 @@ class Reline::LineEditor
prompt_width = calculate_width(prompt_list[@line_index], true)
line_before_cursor = whole_lines[@line_index].byteslice(0, @byte_pointer)
wrapped_line_before_cursor = split_by_width(' ' * prompt_width + line_before_cursor, screen_width).first.compact
- wrapped_cursor_y = wrapped_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
+ wrapped_cursor_y = wrapped_prompt_and_input_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
wrapped_cursor_x = calculate_width(wrapped_line_before_cursor.last)
[wrapped_cursor_x, wrapped_cursor_y]
end
@@ -490,8 +500,9 @@ class Reline::LineEditor
wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
rendered_lines = @rendered_screen.lines
- new_lines = wrapped_lines.flatten[screen_scroll_top, screen_height].map do |l|
- [[0, Reline::Unicode.calculate_width(l, true), l]]
+ new_lines = wrapped_prompt_and_input_lines.flatten(1)[screen_scroll_top, screen_height].map do |prompt, line|
+ prompt_width = Reline::Unicode.calculate_width(prompt, true)
+ [[0, prompt_width, prompt], [prompt_width, Reline::Unicode.calculate_width(line, true), line]]
end
if @menu_info
@menu_info.lines(screen_width).each do |item|
@@ -507,7 +518,8 @@ class Reline::LineEditor
y_range.each do |row|
next if row < 0 || row >= screen_height
dialog_rows = new_lines[row] ||= []
- dialog_rows[index + 1] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
+ # index 0 is for prompt, index 1 is for line, index 2.. is for dialog
+ dialog_rows[index + 2] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
end
end
@@ -692,13 +704,6 @@ class Reline::LineEditor
DIALOG_DEFAULT_HEIGHT = 20
- private def padding_space_with_escape_sequences(str, width)
- padding_width = width - calculate_width(str, true)
- # padding_width should be only positive value. But macOS and Alacritty returns negative value.
- padding_width = 0 if padding_width < 0
- str + (' ' * padding_width)
- end
-
private def dialog_range(dialog, dialog_y)
x_range = dialog.column...dialog.column + dialog.width
y_range = dialog_y + dialog.vertical_offset...dialog_y + dialog.vertical_offset + dialog.contents.size
@@ -771,7 +776,7 @@ class Reline::LineEditor
dialog.contents = contents.map.with_index do |item, i|
line_sgr = i == pointer ? enhanced_sgr : default_sgr
str_width = dialog.width - (scrollbar_pos.nil? ? 0 : @block_elem_width)
- str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
+ str, = Reline::Unicode.take_mbchar_range(item, 0, str_width, padding: true)
colored_content = "#{line_sgr}#{str}"
if scrollbar_pos
if scrollbar_pos <= (i * 2) and (i * 2 + 1) < (scrollbar_pos + bar_height)
@@ -851,7 +856,7 @@ class Reline::LineEditor
[target, preposing, completed, postposing]
end
- private def complete(list, just_show_list)
+ private def perform_completion(list, just_show_list)
case @completion_state
when CompletionState::NORMAL
@completion_state = CompletionState::COMPLETION
@@ -880,10 +885,12 @@ class Reline::LineEditor
@completion_state = CompletionState::PERFECT_MATCH
else
@completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
+ perform_completion(list, true) if @config.show_all_if_ambiguous
end
@perfect_matched = completed
else
@completion_state = CompletionState::MENU
+ perform_completion(list, true) if @config.show_all_if_ambiguous
end
if not just_show_list and target < completed
@buffer_of_lines[@line_index] = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
@@ -942,7 +949,8 @@ class Reline::LineEditor
unless @waiting_proc
byte_pointer_diff = @byte_pointer - old_byte_pointer
@byte_pointer = old_byte_pointer
- send(@vi_waiting_operator, byte_pointer_diff)
+ method_obj = method(@vi_waiting_operator)
+ wrap_method_call(@vi_waiting_operator, method_obj, byte_pointer_diff)
cleanup_waiting
end
else
@@ -1003,7 +1011,8 @@ class Reline::LineEditor
if @vi_waiting_operator
byte_pointer_diff = @byte_pointer - old_byte_pointer
@byte_pointer = old_byte_pointer
- send(@vi_waiting_operator, byte_pointer_diff)
+ method_obj = method(@vi_waiting_operator)
+ wrap_method_call(@vi_waiting_operator, method_obj, byte_pointer_diff)
cleanup_waiting
end
@kill_ring.process
@@ -1058,10 +1067,6 @@ class Reline::LineEditor
end
private def normal_char(key)
- if key.combined_char.is_a?(Symbol)
- process_key(key.combined_char, key.combined_char)
- return
- end
@multibyte_buffer << key.combined_char
if @multibyte_buffer.size > 1
if @multibyte_buffer.dup.force_encoding(@encoding).valid_encoding?
@@ -1104,6 +1109,7 @@ class Reline::LineEditor
end
def input_key(key)
+ save_old_buffer
@config.reset_oneshot_key_bindings
@dialogs.each do |dialog|
if key.char.instance_of?(Symbol) and key.char == dialog.name
@@ -1111,38 +1117,17 @@ class Reline::LineEditor
end
end
if key.char.nil?
+ process_insert(force: true)
if @first_char
@eof = true
end
finish
return
end
- old_lines = @buffer_of_lines.dup
@first_char = false
@completion_occurs = false
- if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
- if !@config.disable_completion
- process_insert(force: true)
- if @config.autocompletion
- @completion_state = CompletionState::NORMAL
- @completion_occurs = move_completed_list(:down)
- else
- @completion_journey_state = nil
- result = call_completion_proc
- if result.is_a?(Array)
- @completion_occurs = true
- complete(result, false)
- end
- end
- end
- elsif @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
- # In vi mode, move completed list even if autocompletion is off
- if not @config.disable_completion
- process_insert(force: true)
- @completion_state = CompletionState::NORMAL
- @completion_occurs = move_completed_list("\C-p".ord == key.char ? :up : :down)
- end
- elsif Symbol === key.char and respond_to?(key.char, true)
+
+ if key.char.is_a?(Symbol)
process_key(key.char, key.char)
else
normal_char(key)
@@ -1152,12 +1137,15 @@ class Reline::LineEditor
@completion_journey_state = nil
end
+ push_past_lines unless @undoing
+ @undoing = false
+
if @in_pasting
clear_dialogs
return
end
- modified = old_lines != @buffer_of_lines
+ modified = @old_buffer_of_lines != @buffer_of_lines
if !@completion_occurs && modified && !@config.disable_completion && @config.autocompletion
# Auto complete starts only when edited
process_insert(force: true)
@@ -1166,6 +1154,26 @@ class Reline::LineEditor
modified
end
+ def save_old_buffer
+ @old_buffer_of_lines = @buffer_of_lines.dup
+ @old_byte_pointer = @byte_pointer.dup
+ @old_line_index = @line_index.dup
+ end
+
+ def push_past_lines
+ if @old_buffer_of_lines != @buffer_of_lines
+ @past_lines.push([@old_buffer_of_lines, @old_byte_pointer, @old_line_index])
+ end
+ trim_past_lines
+ end
+
+ MAX_PAST_LINES = 100
+ def trim_past_lines
+ if @past_lines.size > MAX_PAST_LINES
+ @past_lines.shift
+ end
+ end
+
def scroll_into_view
_wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
if wrapped_cursor_y < screen_scroll_top
@@ -1242,6 +1250,18 @@ class Reline::LineEditor
process_auto_indent
end
+ def set_current_lines(lines, byte_pointer = nil, line_index = 0)
+ cursor = current_byte_pointer_cursor
+ @buffer_of_lines = lines
+ @line_index = line_index
+ if byte_pointer
+ @byte_pointer = byte_pointer
+ else
+ calculate_nearest_cursor(cursor)
+ end
+ process_auto_indent
+ end
+
def retrieve_completion_block(set_completion_quote_character = false)
if Reline.completer_word_break_characters.empty?
word_break_regexp = nil
@@ -1323,6 +1343,18 @@ class Reline::LineEditor
@confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n")
end
+ def insert_pasted_text(text)
+ save_old_buffer
+ pre = @buffer_of_lines[@line_index].byteslice(0, @byte_pointer)
+ post = @buffer_of_lines[@line_index].byteslice(@byte_pointer..)
+ lines = (pre + text.gsub(/\r\n?/, "\n") + post).split("\n", -1)
+ lines << '' if lines.empty?
+ @buffer_of_lines[@line_index, 1] = lines
+ @line_index += lines.size - 1
+ @byte_pointer = @buffer_of_lines[@line_index].bytesize - post.bytesize
+ push_past_lines
+ end
+
def insert_text(text)
if @buffer_of_lines[@line_index].bytesize == @byte_pointer
@buffer_of_lines[@line_index] += text
@@ -1421,13 +1453,42 @@ class Reline::LineEditor
end
end
- private def completion_journey_up(key)
- if not @config.disable_completion and @config.autocompletion
+ private def complete(_key)
+ return if @config.disable_completion
+
+ process_insert(force: true)
+ if @config.autocompletion
@completion_state = CompletionState::NORMAL
- @completion_occurs = move_completed_list(:up)
+ @completion_occurs = move_completed_list(:down)
+ else
+ @completion_journey_state = nil
+ result = call_completion_proc
+ if result.is_a?(Array)
+ @completion_occurs = true
+ perform_completion(result, false)
+ end
end
end
- alias_method :menu_complete_backward, :completion_journey_up
+
+ private def completion_journey_move(direction)
+ return if @config.disable_completion
+
+ process_insert(force: true)
+ @completion_state = CompletionState::NORMAL
+ @completion_occurs = move_completed_list(direction)
+ end
+
+ private def menu_complete(_key)
+ completion_journey_move(:down)
+ end
+
+ private def menu_complete_backward(_key)
+ completion_journey_move(:up)
+ end
+
+ private def completion_journey_up(_key)
+ completion_journey_move(:up) if @config.autocompletion
+ end
# Editline:: +ed-unassigned+ This editor command always results in an error.
# GNU Readline:: There is no corresponding macro.
@@ -1533,11 +1594,7 @@ class Reline::LineEditor
alias_method :vi_zero, :ed_move_to_beg
private def ed_move_to_end(key)
- @byte_pointer = 0
- while @byte_pointer < current_line.bytesize
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- @byte_pointer += byte_size
- end
+ @byte_pointer = current_line.bytesize
end
alias_method :end_of_line, :ed_move_to_end
@@ -1720,7 +1777,6 @@ class Reline::LineEditor
return if @history_pointer.nil?
history_range = @history_pointer + 1...Reline::HISTORY.size
- history = Reline::HISTORY.slice((@history_pointer + 1)..-1)
h_pointer, line_index = search_history(substr, history_range)
return if h_pointer.nil? and not substr.empty?
@@ -1901,7 +1957,7 @@ class Reline::LineEditor
elsif !@config.autocompletion # show completed list
result = call_completion_proc
if result.is_a?(Array)
- complete(result, true)
+ perform_completion(result, true)
end
end
end
@@ -2471,4 +2527,15 @@ class Reline::LineEditor
private def vi_editing_mode(key)
@config.editing_mode = :vi_insert
end
+
+ private def undo(_key)
+ return if @past_lines.empty?
+
+ @undoing = true
+
+ target_lines, target_cursor_x, target_cursor_y = @past_lines.last
+ set_current_lines(target_lines, target_cursor_x, target_cursor_y)
+
+ @past_lines.pop
+ end
end
diff --git a/lib/reline/unicode.rb b/lib/reline/unicode.rb
index 26ef207ba6..d7460d6d4a 100644
--- a/lib/reline/unicode.rb
+++ b/lib/reline/unicode.rb
@@ -43,11 +43,13 @@ class Reline::Unicode
def self.escape_for_print(str)
str.chars.map! { |gr|
- escaped = EscapedPairs[gr.ord]
- if escaped && gr != -"\n" && gr != -"\t"
- escaped
- else
+ case gr
+ when -"\n"
gr
+ when -"\t"
+ -' '
+ else
+ EscapedPairs[gr.ord] || gr
end
}.join
end
@@ -128,10 +130,10 @@ class Reline::Unicode
end
end
- def self.split_by_width(str, max_width, encoding = str.encoding)
+ def self.split_by_width(str, max_width, encoding = str.encoding, offset: 0)
lines = [String.new(encoding: encoding)]
height = 1
- width = 0
+ width = offset
rest = str.encode(Encoding::UTF_8)
in_zero_width = false
seq = String.new(encoding: encoding)
@@ -145,7 +147,13 @@ class Reline::Unicode
lines.last << NON_PRINTING_END
when csi
lines.last << csi
- seq << csi
+ unless in_zero_width
+ if csi == -"\e[m" || csi == -"\e[0m"
+ seq.clear
+ else
+ seq << csi
+ end
+ end
when osc
lines.last << osc
seq << osc
@@ -173,32 +181,78 @@ class Reline::Unicode
# Take a chunk of a String cut by width with escape sequences.
def self.take_range(str, start_col, max_width)
+ take_mbchar_range(str, start_col, max_width).first
+ end
+
+ def self.take_mbchar_range(str, start_col, width, cover_begin: false, cover_end: false, padding: false)
chunk = String.new(encoding: str.encoding)
+
+ end_col = start_col + width
total_width = 0
rest = str.encode(Encoding::UTF_8)
in_zero_width = false
+ chunk_start_col = nil
+ chunk_end_col = nil
+ has_csi = false
rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
case
when non_printing_start
in_zero_width = true
+ chunk << NON_PRINTING_START
when non_printing_end
in_zero_width = false
+ chunk << NON_PRINTING_END
when csi
+ has_csi = true
chunk << csi
when osc
chunk << osc
when gc
if in_zero_width
chunk << gc
+ next
+ end
+
+ mbchar_width = get_mbchar_width(gc)
+ prev_width = total_width
+ total_width += mbchar_width
+
+ if (cover_begin || padding ? total_width <= start_col : prev_width < start_col)
+ # Current character haven't reached start_col yet
+ next
+ elsif padding && !cover_begin && prev_width < start_col && start_col < total_width
+ # Add preceding padding. This padding might have background color.
+ chunk << ' '
+ chunk_start_col ||= start_col
+ chunk_end_col = total_width
+ next
+ elsif (cover_end ? prev_width < end_col : total_width <= end_col)
+ # Current character is in the range
+ chunk << gc
+ chunk_start_col ||= prev_width
+ chunk_end_col = total_width
+ break if total_width >= end_col
else
- mbchar_width = get_mbchar_width(gc)
- total_width += mbchar_width
- break if (start_col + max_width) < total_width
- chunk << gc if start_col < total_width
+ # Current character exceeds end_col
+ if padding && end_col < total_width
+ # Add succeeding padding. This padding might have background color.
+ chunk << ' '
+ chunk_start_col ||= prev_width
+ chunk_end_col = end_col
+ end
+ break
end
end
end
- chunk
+ chunk_start_col ||= start_col
+ chunk_end_col ||= start_col
+ if padding && chunk_end_col < end_col
+ # Append padding. This padding should not include background color.
+ chunk << "\e[0m" if has_csi
+ chunk << ' ' * (end_col - chunk_end_col)
+ chunk_end_col = end_col
+ end
+ [chunk, chunk_start_col, chunk_end_col - chunk_start_col]
end
def self.get_next_mbchar_size(line, byte_pointer)
diff --git a/lib/reline/version.rb b/lib/reline/version.rb
index e6f370c6ec..46613a5952 100644
--- a/lib/reline/version.rb
+++ b/lib/reline/version.rb
@@ -1,3 +1,3 @@
module Reline
- VERSION = '0.5.2'
+ VERSION = '0.5.7'
end
diff --git a/lib/ruby_vm/rjit/insn_compiler.rb b/lib/ruby_vm/rjit/insn_compiler.rb
index 2346c92bd1..f9450241c9 100644
--- a/lib/ruby_vm/rjit/insn_compiler.rb
+++ b/lib/ruby_vm/rjit/insn_compiler.rb
@@ -5461,6 +5461,12 @@ module RubyVM::RJIT
return CantCompile
end
+ if c_method_tracing_currently_enabled?
+ # Don't JIT if tracing c_call or c_return
+ asm.incr_counter(:send_cfunc_tracing)
+ return CantCompile
+ end
+
off = cme.def.body.optimized.index
recv_idx = argc # blockarg is not supported
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index ad7ab10756..ac225ca70a 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -1013,6 +1013,13 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
##
+ # Is this platform FreeBSD
+
+ def self.freebsd_platform?
+ RbConfig::CONFIG["host_os"].to_s.include?("bsd")
+ end
+
+ ##
# Load +plugins+ as Ruby files
def self.load_plugin_files(plugins) # :nodoc:
diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb
index 456d897df2..b272a15b6c 100644
--- a/lib/rubygems/commands/pristine_command.rb
+++ b/lib/rubygems/commands/pristine_command.rb
@@ -57,7 +57,7 @@ class Gem::Commands::PristineCommand < Gem::Command
end
add_option("-i", "--install-dir DIR",
- "Gem repository to get binstubs and plugins installed") do |value, options|
+ "Gem repository to get gems restored") do |value, options|
options[:install_dir] = File.expand_path(value)
end
@@ -103,21 +103,25 @@ extensions will be restored.
end
def execute
+ install_dir = options[:install_dir]
+
+ specification_record = install_dir ? Gem::SpecificationRecord.from_path(install_dir) : Gem::Specification.specification_record
+
specs = if options[:all]
- Gem::Specification.map
+ specification_record.map
# `--extensions` must be explicitly given to pristine only gems
# with extensions.
elsif options[:extensions_set] &&
options[:extensions] && options[:args].empty?
- Gem::Specification.select do |spec|
+ specification_record.select do |spec|
spec.extensions && !spec.extensions.empty?
end
elsif options[:only_missing_extensions]
- Gem::Specification.select(&:missing_extensions?)
+ specification_record.select(&:missing_extensions?)
else
get_all_gem_names.sort.map do |gem_name|
- Gem::Specification.find_all_by_name(gem_name, options[:version]).reverse
+ specification_record.find_all_by_name(gem_name, options[:version]).reverse
end.flatten
end
@@ -176,7 +180,6 @@ extensions will be restored.
end
bin_dir = options[:bin_dir] if options[:bin_dir]
- install_dir = options[:install_dir] if options[:install_dir]
installer_options = {
wrappers: true,
diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb
index 3f38074280..9c633d6ef7 100644
--- a/lib/rubygems/commands/setup_command.rb
+++ b/lib/rubygems/commands/setup_command.rb
@@ -585,6 +585,8 @@ abort "#{deprecation_message}"
args = %w[--all --only-executables --silent]
args << "--bindir=#{bindir}"
+ args << "--install-dir=#{default_dir}"
+
if options[:env_shebang]
args << "--env-shebang"
end
diff --git a/lib/rubygems/commands/uninstall_command.rb b/lib/rubygems/commands/uninstall_command.rb
index 2a77ec72cf..283bc96ce3 100644
--- a/lib/rubygems/commands/uninstall_command.rb
+++ b/lib/rubygems/commands/uninstall_command.rb
@@ -184,7 +184,7 @@ that is a dependency of an existing gem. You can use the
rescue Gem::GemNotInHomeException => e
spec = e.spec
alert("In order to remove #{spec.name}, please execute:\n" \
- "\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}")
+ "\tgem uninstall #{spec.name} --install-dir=#{spec.base_dir}")
rescue Gem::UninstallError => e
spec = e.spec
alert_error("Error: unable to successfully uninstall '#{spec.name}' which is " \
diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb
index 3d6fecaa40..8e80d46856 100644
--- a/lib/rubygems/commands/update_command.rb
+++ b/lib/rubygems/commands/update_command.rb
@@ -197,18 +197,17 @@ command to remove old versions.
yield
else
require "tmpdir"
- tmpdir = Dir.mktmpdir
- FileUtils.mv Gem.plugindir, tmpdir
+ Dir.mktmpdir("gem_update") do |tmpdir|
+ FileUtils.mv Gem.plugindir, tmpdir
- status = yield
+ status = yield
- if status
- FileUtils.rm_rf tmpdir
- else
- FileUtils.mv File.join(tmpdir, "plugins"), Gem.plugindir
- end
+ unless status
+ FileUtils.mv File.join(tmpdir, "plugins"), Gem.plugindir
+ end
- status
+ status
+ end
end
end
diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb
index d1bf074441..5ce9c5e840 100644
--- a/lib/rubygems/dependency.rb
+++ b/lib/rubygems/dependency.rb
@@ -271,15 +271,7 @@ class Gem::Dependency
end
def matching_specs(platform_only = false)
- env_req = Gem.env_requirement(name)
- matches = Gem::Specification.stubs_for(name).find_all do |spec|
- requirement.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
- end.map(&:to_spec)
-
- if prioritizes_bundler?
- require_relative "bundler_version_finder"
- Gem::BundlerVersionFinder.prioritize!(matches)
- end
+ matches = Gem::Specification.find_all_by_name(name, requirement)
if platform_only
matches.reject! do |spec|
@@ -297,10 +289,6 @@ class Gem::Dependency
@requirement.specific?
end
- def prioritizes_bundler?
- name == "bundler" && !specific?
- end
-
def to_specs
matches = matching_specs true
diff --git a/lib/rubygems/deprecate.rb b/lib/rubygems/deprecate.rb
index 58a6c5b7dc..7d24f9cbfc 100644
--- a/lib/rubygems/deprecate.rb
+++ b/lib/rubygems/deprecate.rb
@@ -69,99 +69,101 @@
# end
# end
-module Gem::Deprecate
- def self.skip # :nodoc:
- @skip ||= false
- end
+module Gem
+ module Deprecate
+ def self.skip # :nodoc:
+ @skip ||= false
+ end
- def self.skip=(v) # :nodoc:
- @skip = v
- end
+ def self.skip=(v) # :nodoc:
+ @skip = v
+ end
- ##
- # Temporarily turn off warnings. Intended for tests only.
+ ##
+ # Temporarily turn off warnings. Intended for tests only.
- def skip_during
- original = Gem::Deprecate.skip
- Gem::Deprecate.skip = true
- yield
- ensure
- Gem::Deprecate.skip = original
- end
+ def skip_during
+ original = Gem::Deprecate.skip
+ Gem::Deprecate.skip = true
+ yield
+ ensure
+ Gem::Deprecate.skip = original
+ end
- def self.next_rubygems_major_version # :nodoc:
- Gem::Version.new(Gem.rubygems_version.segments.first).bump
- end
+ def self.next_rubygems_major_version # :nodoc:
+ Gem::Version.new(Gem.rubygems_version.segments.first).bump
+ end
- ##
- # Simple deprecation method that deprecates +name+ by wrapping it up
- # in a dummy method. It warns on each call to the dummy method
- # telling the user of +repl+ (unless +repl+ is :none) and the
- # year/month that it is planned to go away.
+ ##
+ # Simple deprecation method that deprecates +name+ by wrapping it up
+ # in a dummy method. It warns on each call to the dummy method
+ # telling the user of +repl+ (unless +repl+ is :none) and the
+ # year/month that it is planned to go away.
- def deprecate(name, repl, year, month)
- class_eval do
- old = "_deprecated_#{name}"
- alias_method old, name
- define_method name do |*args, &block|
- klass = is_a? Module
- target = klass ? "#{self}." : "#{self.class}#"
- msg = [
- "NOTE: #{target}#{name} is deprecated",
- repl == :none ? " with no replacement" : "; use #{repl} instead",
- format(". It will be removed on or after %4d-%02d.", year, month),
- "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
- ]
- warn "#{msg.join}." unless Gem::Deprecate.skip
- send old, *args, &block
+ def deprecate(name, repl, year, month)
+ class_eval do
+ old = "_deprecated_#{name}"
+ alias_method old, name
+ define_method name do |*args, &block|
+ klass = is_a? Module
+ target = klass ? "#{self}." : "#{self.class}#"
+ msg = [
+ "NOTE: #{target}#{name} is deprecated",
+ repl == :none ? " with no replacement" : "; use #{repl} instead",
+ format(". It will be removed on or after %4d-%02d.", year, month),
+ "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
+ ]
+ warn "#{msg.join}." unless Gem::Deprecate.skip
+ send old, *args, &block
+ end
+ ruby2_keywords name if respond_to?(:ruby2_keywords, true)
end
- ruby2_keywords name if respond_to?(:ruby2_keywords, true)
end
- end
- ##
- # Simple deprecation method that deprecates +name+ by wrapping it up
- # in a dummy method. It warns on each call to the dummy method
- # telling the user of +repl+ (unless +repl+ is :none) and the
- # Rubygems version that it is planned to go away.
+ ##
+ # Simple deprecation method that deprecates +name+ by wrapping it up
+ # in a dummy method. It warns on each call to the dummy method
+ # telling the user of +repl+ (unless +repl+ is :none) and the
+ # Rubygems version that it is planned to go away.
- def rubygems_deprecate(name, replacement=:none)
- class_eval do
- old = "_deprecated_#{name}"
- alias_method old, name
- define_method name do |*args, &block|
- klass = is_a? Module
- target = klass ? "#{self}." : "#{self.class}#"
- msg = [
- "NOTE: #{target}#{name} is deprecated",
- replacement == :none ? " with no replacement" : "; use #{replacement} instead",
- ". It will be removed in Rubygems #{Gem::Deprecate.next_rubygems_major_version}",
- "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
- ]
- warn "#{msg.join}." unless Gem::Deprecate.skip
- send old, *args, &block
+ def rubygems_deprecate(name, replacement=:none)
+ class_eval do
+ old = "_deprecated_#{name}"
+ alias_method old, name
+ define_method name do |*args, &block|
+ klass = is_a? Module
+ target = klass ? "#{self}." : "#{self.class}#"
+ msg = [
+ "NOTE: #{target}#{name} is deprecated",
+ replacement == :none ? " with no replacement" : "; use #{replacement} instead",
+ ". It will be removed in Rubygems #{Gem::Deprecate.next_rubygems_major_version}",
+ "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
+ ]
+ warn "#{msg.join}." unless Gem::Deprecate.skip
+ send old, *args, &block
+ end
+ ruby2_keywords name if respond_to?(:ruby2_keywords, true)
end
- ruby2_keywords name if respond_to?(:ruby2_keywords, true)
end
- end
- # Deprecation method to deprecate Rubygems commands
- def rubygems_deprecate_command(version = Gem::Deprecate.next_rubygems_major_version)
- class_eval do
- define_method "deprecated?" do
- true
- end
+ # Deprecation method to deprecate Rubygems commands
+ def rubygems_deprecate_command(version = Gem::Deprecate.next_rubygems_major_version)
+ class_eval do
+ define_method "deprecated?" do
+ true
+ end
- define_method "deprecation_warning" do
- msg = [
- "#{command} command is deprecated",
- ". It will be removed in Rubygems #{version}.\n",
- ]
+ define_method "deprecation_warning" do
+ msg = [
+ "#{command} command is deprecated",
+ ". It will be removed in Rubygems #{version}.\n",
+ ]
- alert_warning msg.join.to_s unless Gem::Deprecate.skip
+ alert_warning msg.join.to_s unless Gem::Deprecate.skip
+ end
end
end
- end
- module_function :rubygems_deprecate, :rubygems_deprecate_command, :skip_during
+ module_function :rubygems_deprecate, :rubygems_deprecate_command, :skip_during
+ end
end
diff --git a/lib/rubygems/ext/cargo_builder.rb b/lib/rubygems/ext/cargo_builder.rb
index 86a0e73f28..09ad1407c2 100644
--- a/lib/rubygems/ext/cargo_builder.rb
+++ b/lib/rubygems/ext/cargo_builder.rb
@@ -184,6 +184,7 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
end
def cargo_dylib_path(dest_path, crate_name)
+ so_ext = RbConfig::CONFIG["SOEXT"]
prefix = so_ext == "dll" ? "" : "lib"
path_parts = [dest_path]
path_parts << ENV["CARGO_BUILD_TARGET"] if ENV["CARGO_BUILD_TARGET"]
@@ -312,22 +313,6 @@ EOF
deffile_path
end
- # We have to basically reimplement <code>RbConfig::CONFIG['SOEXT']</code> here to support
- # Ruby < 2.5
- #
- # @see https://github.com/ruby/ruby/blob/c87c027f18c005460746a74c07cd80ee355b16e4/configure.ac#L3185
- def so_ext
- return RbConfig::CONFIG["SOEXT"] if RbConfig::CONFIG.key?("SOEXT")
-
- if win_target?
- "dll"
- elsif darwin_target?
- "dylib"
- else
- "so"
- end
- end
-
# Corresponds to $(LIBPATH) in mkmf
def mkmf_libpath
["-L", "native=#{makefile_config("libdir")}"]
diff --git a/lib/rubygems/gemcutter_utilities/webauthn_poller.rb b/lib/rubygems/gemcutter_utilities/webauthn_poller.rb
index 0fdd1d5bf4..fe3f163a88 100644
--- a/lib/rubygems/gemcutter_utilities/webauthn_poller.rb
+++ b/lib/rubygems/gemcutter_utilities/webauthn_poller.rb
@@ -69,8 +69,10 @@ module Gem::GemcutterUtilities
rubygems_api_request(:get, "api/v1/webauthn_verification/#{webauthn_token}/status.json") do |request|
if credentials.empty?
request.add_field "Authorization", api_key
+ elsif credentials[:identifier] && credentials[:password]
+ request.basic_auth credentials[:identifier], credentials[:password]
else
- request.basic_auth credentials[:email], credentials[:password]
+ raise Gem::WebauthnVerificationError, "Provided missing credentials"
end
end
end
diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb
index 8f6f9a5aa8..844f292ba2 100644
--- a/lib/rubygems/installer.rb
+++ b/lib/rubygems/installer.rb
@@ -344,7 +344,7 @@ class Gem::Installer
say spec.post_install_message if options[:post_install_message] && !spec.post_install_message.nil?
- Gem::Specification.add_spec(spec)
+ Gem::Specification.add_spec(spec) unless @install_dir
load_plugin
diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb
index 1d5d764237..c855423ed7 100644
--- a/lib/rubygems/package.rb
+++ b/lib/rubygems/package.rb
@@ -7,7 +7,6 @@
# rubocop:enable Style/AsciiComments
-require_relative "../rubygems"
require_relative "security"
require_relative "user_interaction"
@@ -295,7 +294,6 @@ class Gem::Package
Gem.load_yaml
- @spec.mark_version
@spec.validate true, strict_validation unless skip_validation
setup_signer(
@@ -528,12 +526,13 @@ EOM
# Loads a Gem::Specification from the TarEntry +entry+
def load_spec(entry) # :nodoc:
+ limit = 10 * 1024 * 1024
case entry.full_name
when "metadata" then
- @spec = Gem::Specification.from_yaml entry.read
+ @spec = Gem::Specification.from_yaml limit_read(entry, "metadata", limit)
when "metadata.gz" then
Zlib::GzipReader.wrap(entry, external_encoding: Encoding::UTF_8) do |gzio|
- @spec = Gem::Specification.from_yaml gzio.read
+ @spec = Gem::Specification.from_yaml limit_read(gzio, "metadata.gz", limit)
end
end
end
@@ -557,7 +556,7 @@ EOM
@checksums = gem.seek "checksums.yaml.gz" do |entry|
Zlib::GzipReader.wrap entry do |gz_io|
- Gem::SafeYAML.safe_load gz_io.read
+ Gem::SafeYAML.safe_load limit_read(gz_io, "checksums.yaml.gz", 10 * 1024 * 1024)
end
end
end
@@ -664,7 +663,7 @@ EOM
case file_name
when /\.sig$/ then
- @signatures[$`] = entry.read if @security_policy
+ @signatures[$`] = limit_read(entry, file_name, 1024 * 1024) if @security_policy
return
else
digest entry
@@ -724,6 +723,12 @@ EOM
IO.copy_stream(src, dst)
end
end
+
+ def limit_read(io, name, limit)
+ bytes = io.read(limit + 1)
+ raise Gem::Package::FormatError, "#{name} is too big (over #{limit} bytes)" if bytes.size > limit
+ bytes
+ end
end
require_relative "package/digest_io"
diff --git a/lib/rubygems/package/tar_header.rb b/lib/rubygems/package/tar_header.rb
index 087f13f6c9..dd5e835a1e 100644
--- a/lib/rubygems/package/tar_header.rb
+++ b/lib/rubygems/package/tar_header.rb
@@ -95,14 +95,14 @@ class Gem::Package::TarHeader
attr_reader(*FIELDS)
- EMPTY_HEADER = ("\0" * 512).freeze # :nodoc:
+ EMPTY_HEADER = ("\0" * 512).b.freeze # :nodoc:
##
# Creates a tar header from IO +stream+
def self.from(stream)
header = stream.read 512
- empty = (header == EMPTY_HEADER)
+ return EMPTY if header == EMPTY_HEADER
fields = header.unpack UNPACK_FORMAT
@@ -123,7 +123,7 @@ class Gem::Package::TarHeader
devminor: strict_oct(fields.shift),
prefix: fields.shift,
- empty: empty
+ empty: false
end
def self.strict_oct(str)
@@ -172,6 +172,22 @@ class Gem::Package::TarHeader
@empty = vals[:empty]
end
+ EMPTY = new({ # :nodoc:
+ checksum: 0,
+ gname: "",
+ linkname: "",
+ magic: "",
+ mode: 0,
+ name: "",
+ prefix: "",
+ size: 0,
+ uname: "",
+ version: 0,
+
+ empty: true,
+ }).freeze
+ private_constant :EMPTY
+
##
# Is the tar entry empty?
@@ -241,7 +257,7 @@ class Gem::Package::TarHeader
header = header.pack PACK_FORMAT
- header << ("\0" * ((512 - header.size) % 512))
+ header.ljust 512, "\0"
end
def oct(num, len)
diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb
index 48b7344aee..d54ad12880 100644
--- a/lib/rubygems/platform.rb
+++ b/lib/rubygems/platform.rb
@@ -134,6 +134,7 @@ class Gem::Platform
when /netbsdelf/ then ["netbsdelf", nil]
when /openbsd(\d+\.\d+)?/ then ["openbsd", $1]
when /solaris(\d+\.\d+)?/ then ["solaris", $1]
+ when /wasi/ then ["wasi", nil]
# test
when /^(\w+_platform)(\d+)?/ then [$1, $2]
else ["unknown", nil]
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index 29139cf725..57f9b45cf7 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -11,6 +11,7 @@ require_relative "deprecate"
require_relative "basic_specification"
require_relative "stub_specification"
require_relative "platform"
+require_relative "specification_record"
require_relative "util/list"
require "rbconfig"
@@ -179,22 +180,12 @@ class Gem::Specification < Gem::BasicSpecification
@@default_value[k].nil?
end
- def self.clear_specs # :nodoc:
- @@all = nil
- @@stubs = nil
- @@stubs_by_name = {}
- @@spec_with_requirable_file = {}
- @@active_stub_with_requirable_file = {}
- end
- private_class_method :clear_specs
-
- clear_specs
-
# Sentinel object to represent "not found" stubs
NOT_FOUND = Struct.new(:to_spec, :this).new # :nodoc:
+ deprecate_constant :NOT_FOUND
# Tracking removed method calls to warn users during build time.
- REMOVED_METHODS = [:rubyforge_project=].freeze # :nodoc:
+ REMOVED_METHODS = [:rubyforge_project=, :mark_version].freeze # :nodoc:
def removed_method_calls
@removed_method_calls ||= []
end
@@ -770,7 +761,7 @@ class Gem::Specification < Gem::BasicSpecification
attr_accessor :specification_version
def self._all # :nodoc:
- @@all ||= Gem.loaded_specs.values | stubs.map(&:to_spec)
+ specification_record.all
end
def self.clear_load_cache # :nodoc:
@@ -788,26 +779,9 @@ class Gem::Specification < Gem::BasicSpecification
end
end
- def self.gemspec_stubs_in(dir, pattern)
+ def self.gemspec_stubs_in(dir, pattern) # :nodoc:
Gem::Util.glob_files_in_dir(pattern, dir).map {|path| yield path }.select(&:valid?)
end
- private_class_method :gemspec_stubs_in
-
- def self.installed_stubs(dirs, pattern)
- map_stubs(dirs, pattern) do |path, base_dir, gems_dir|
- Gem::StubSpecification.gemspec_stub(path, base_dir, gems_dir)
- end
- end
- private_class_method :installed_stubs
-
- def self.map_stubs(dirs, pattern) # :nodoc:
- dirs.flat_map do |dir|
- base_dir = File.dirname dir
- gems_dir = File.join base_dir, "gems"
- gemspec_stubs_in(dir, pattern) {|path| yield path, base_dir, gems_dir }
- end
- end
- private_class_method :map_stubs
def self.each_spec(dirs) # :nodoc:
each_gemspec(dirs) do |path|
@@ -820,13 +794,7 @@ class Gem::Specification < Gem::BasicSpecification
# Returns a Gem::StubSpecification for every installed gem
def self.stubs
- @@stubs ||= begin
- pattern = "*.gemspec"
- stubs = stubs_for_pattern(pattern, false)
-
- @@stubs_by_name = stubs.select {|s| Gem::Platform.match_spec? s }.group_by(&:name)
- stubs
- end
+ specification_record.stubs
end
##
@@ -845,13 +813,7 @@ class Gem::Specification < Gem::BasicSpecification
# only returns stubs that match Gem.platforms
def self.stubs_for(name)
- if @@stubs
- @@stubs_by_name[name] || []
- else
- @@stubs_by_name[name] ||= stubs_for_pattern("#{name}-*.gemspec").select do |s|
- s.name == name
- end
- end
+ specification_record.stubs_for(name)
end
##
@@ -859,12 +821,7 @@ class Gem::Specification < Gem::BasicSpecification
# optionally filtering out specs not matching the current platform
#
def self.stubs_for_pattern(pattern, match_platform = true) # :nodoc:
- installed_stubs = installed_stubs(Gem::Specification.dirs, pattern)
- installed_stubs.select! {|s| Gem::Platform.match_spec? s } if match_platform
- stubs = installed_stubs + default_stubs(pattern)
- stubs = stubs.uniq(&:full_name)
- _resort!(stubs)
- stubs
+ specification_record.stubs_for_pattern(pattern, match_platform)
end
def self._resort!(specs) # :nodoc:
@@ -893,23 +850,14 @@ class Gem::Specification < Gem::BasicSpecification
# properly sorted.
def self.add_spec(spec)
- return if _all.include? spec
-
- _all << spec
- stubs << spec
- (@@stubs_by_name[spec.name] ||= []) << spec
-
- _resort!(@@stubs_by_name[spec.name])
- _resort!(stubs)
+ specification_record.add_spec(spec)
end
##
# Removes +spec+ from the known specs.
def self.remove_spec(spec)
- _all.delete spec.to_spec
- stubs.delete spec
- (@@stubs_by_name[spec.name] || []).delete spec
+ specification_record.remove_spec(spec)
end
##
@@ -923,27 +871,17 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # Sets the known specs to +specs+. Not guaranteed to work for you in
- # the future. Use at your own risk. Caveat emptor. Doomy doom doom.
- # Etc etc.
- #
- #--
- # Makes +specs+ the known specs
- # Listen, time is a river
- # Winter comes, code breaks
- #
- # -- wilsonb
+ # Sets the known specs to +specs+.
def self.all=(specs)
- @@stubs_by_name = specs.group_by(&:name)
- @@all = @@stubs = specs
+ specification_record.all = specs
end
##
# Return full names of all specs in sorted order.
def self.all_names
- _all.map(&:full_name)
+ specification_record.all_names
end
##
@@ -968,9 +906,7 @@ class Gem::Specification < Gem::BasicSpecification
# Return the directories that Specification uses to find specs.
def self.dirs
- @@dirs ||= Gem.path.collect do |dir|
- File.join dir, "specifications"
- end
+ @@dirs ||= Gem::SpecificationRecord.dirs_from(Gem.path)
end
##
@@ -980,7 +916,7 @@ class Gem::Specification < Gem::BasicSpecification
def self.dirs=(dirs)
reset
- @@dirs = Array(dirs).map {|dir| File.join dir, "specifications" }
+ @@dirs = Gem::SpecificationRecord.dirs_from(Array(dirs))
end
extend Enumerable
@@ -989,21 +925,15 @@ class Gem::Specification < Gem::BasicSpecification
# Enumerate every known spec. See ::dirs= and ::add_spec to set the list of
# specs.
- def self.each
- return enum_for(:each) unless block_given?
-
- _all.each do |x|
- yield x
- end
+ def self.each(&block)
+ specification_record.each(&block)
end
##
# Returns every spec that matches +name+ and optional +requirements+.
def self.find_all_by_name(name, *requirements)
- requirements = Gem::Requirement.default if requirements.empty?
-
- Gem::Dependency.new(name, *requirements).matching_specs
+ specification_record.find_all_by_name(name, *requirements)
end
##
@@ -1033,12 +963,7 @@ class Gem::Specification < Gem::BasicSpecification
# Return the best specification that contains the file matching +path+.
def self.find_by_path(path)
- path = path.dup.freeze
- spec = @@spec_with_requirable_file[path] ||= stubs.find do |s|
- s.contains_requirable_file? path
- end || NOT_FOUND
-
- spec.to_spec
+ specification_record.find_by_path(path)
end
##
@@ -1046,19 +971,15 @@ class Gem::Specification < Gem::BasicSpecification
# amongst the specs that are not activated.
def self.find_inactive_by_path(path)
- stub = stubs.find do |s|
- next if s.activated?
- s.contains_requirable_file? path
- end
- stub&.to_spec
+ specification_record.find_inactive_by_path(path)
end
- def self.find_active_stub_by_path(path)
- stub = @@active_stub_with_requirable_file[path] ||= stubs.find do |s|
- s.activated? && s.contains_requirable_file?(path)
- end || NOT_FOUND
+ ##
+ # Return the best specification that contains the file matching +path+, among
+ # those already activated.
- stub.this
+ def self.find_active_stub_by_path(path)
+ specification_record.find_active_stub_by_path(path)
end
##
@@ -1125,14 +1046,14 @@ class Gem::Specification < Gem::BasicSpecification
# +prerelease+ is true.
def self.latest_specs(prerelease = false)
- _latest_specs Gem::Specification.stubs, prerelease
+ specification_record.latest_specs(prerelease)
end
##
# Return the latest installed spec for gem +name+.
def self.latest_spec_for(name)
- latest_specs(true).find {|installed_spec| installed_spec.name == name }
+ specification_record.latest_spec_for(name)
end
def self._latest_specs(specs, prerelease = false) # :nodoc:
@@ -1270,7 +1191,7 @@ class Gem::Specification < Gem::BasicSpecification
def self.reset
@@dirs = nil
Gem.pre_reset_hooks.each(&:call)
- clear_specs
+ @specification_record = nil
clear_load_cache
unresolved = unresolved_deps
unless unresolved.empty?
@@ -1291,6 +1212,13 @@ class Gem::Specification < Gem::BasicSpecification
Gem.post_reset_hooks.each(&:call)
end
+ ##
+ # Keeps track of all currently known specifications
+
+ def self.specification_record
+ @specification_record ||= Gem::SpecificationRecord.new(dirs)
+ end
+
# DOC: This method needs documented or nodoc'd
def self.unresolved_deps
@unresolved_deps ||= Hash.new {|h, n| h[n] = Gem::Dependency.new n }
@@ -1874,8 +1802,6 @@ class Gem::Specification < Gem::BasicSpecification
end
def encode_with(coder) # :nodoc:
- mark_version
-
coder.add "name", @name
coder.add "version", @version
platform = case @original_platform
@@ -2171,13 +2097,6 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # Sets the rubygems_version to the current RubyGems version.
-
- def mark_version
- @rubygems_version = Gem::VERSION
- end
-
- ##
# Track removed method calls to warn about during build time.
# Warn about unknown attributes while loading a spec.
@@ -2494,7 +2413,6 @@ class Gem::Specification < Gem::BasicSpecification
# still have their default values are omitted.
def to_ruby
- mark_version
result = []
result << "# -*- encoding: utf-8 -*-"
result << "#{Gem::StubSpecification::PREFIX}#{name} #{version} #{platform} #{raw_require_paths.join("\0")}"
diff --git a/lib/rubygems/specification_policy.rb b/lib/rubygems/specification_policy.rb
index 516c26f53c..812b0f889e 100644
--- a/lib/rubygems/specification_policy.rb
+++ b/lib/rubygems/specification_policy.rb
@@ -274,7 +274,9 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
return if rubygems_version == Gem::VERSION
- error "expected RubyGems version #{Gem::VERSION}, was #{rubygems_version}"
+ warning "expected RubyGems version #{Gem::VERSION}, was #{rubygems_version}"
+
+ @specification.rubygems_version = Gem::VERSION
end
def validate_required_attributes
diff --git a/lib/rubygems/specification_record.rb b/lib/rubygems/specification_record.rb
new file mode 100644
index 0000000000..dd6aa7eafa
--- /dev/null
+++ b/lib/rubygems/specification_record.rb
@@ -0,0 +1,213 @@
+# frozen_string_literal: true
+
+module Gem
+ class SpecificationRecord
+ def self.dirs_from(paths)
+ paths.map do |path|
+ File.join(path, "specifications")
+ end
+ end
+
+ def self.from_path(path)
+ new(dirs_from([path]))
+ end
+
+ def initialize(dirs)
+ @all = nil
+ @stubs = nil
+ @stubs_by_name = {}
+ @spec_with_requirable_file = {}
+ @active_stub_with_requirable_file = {}
+
+ @dirs = dirs
+ end
+
+ # Sentinel object to represent "not found" stubs
+ NOT_FOUND = Struct.new(:to_spec, :this).new
+ private_constant :NOT_FOUND
+
+ ##
+ # Returns the list of all specifications in the record
+
+ def all
+ @all ||= Gem.loaded_specs.values | stubs.map(&:to_spec)
+ end
+
+ ##
+ # Returns a Gem::StubSpecification for every specification in the record
+
+ def stubs
+ @stubs ||= begin
+ pattern = "*.gemspec"
+ stubs = stubs_for_pattern(pattern, false)
+
+ @stubs_by_name = stubs.select {|s| Gem::Platform.match_spec? s }.group_by(&:name)
+ stubs
+ end
+ end
+
+ ##
+ # Returns a Gem::StubSpecification for every specification in the record
+ # named +name+ only returns stubs that match Gem.platforms
+
+ def stubs_for(name)
+ if @stubs
+ @stubs_by_name[name] || []
+ else
+ @stubs_by_name[name] ||= stubs_for_pattern("#{name}-*.gemspec").select do |s|
+ s.name == name
+ end
+ end
+ end
+
+ ##
+ # Finds stub specifications matching a pattern in the record, optionally
+ # filtering out specs not matching the current platform
+
+ def stubs_for_pattern(pattern, match_platform = true)
+ installed_stubs = installed_stubs(pattern)
+ installed_stubs.select! {|s| Gem::Platform.match_spec? s } if match_platform
+ stubs = installed_stubs + Gem::Specification.default_stubs(pattern)
+ stubs = stubs.uniq(&:full_name)
+ Gem::Specification._resort!(stubs)
+ stubs
+ end
+
+ ##
+ # Adds +spec+ to the the record, keeping the collection properly sorted.
+
+ def add_spec(spec)
+ return if all.include? spec
+
+ all << spec
+ stubs << spec
+ (@stubs_by_name[spec.name] ||= []) << spec
+
+ Gem::Specification._resort!(@stubs_by_name[spec.name])
+ Gem::Specification._resort!(stubs)
+ end
+
+ ##
+ # Removes +spec+ from the record.
+
+ def remove_spec(spec)
+ all.delete spec.to_spec
+ stubs.delete spec
+ (@stubs_by_name[spec.name] || []).delete spec
+ end
+
+ ##
+ # Sets the specs known by the record to +specs+.
+
+ def all=(specs)
+ @stubs_by_name = specs.group_by(&:name)
+ @all = @stubs = specs
+ end
+
+ ##
+ # Return full names of all specs in the record in sorted order.
+
+ def all_names
+ all.map(&:full_name)
+ end
+
+ include Enumerable
+
+ ##
+ # Enumerate every known spec.
+
+ def each
+ return enum_for(:each) unless block_given?
+
+ all.each do |x|
+ yield x
+ end
+ end
+
+ ##
+ # Returns every spec in the record that matches +name+ and optional +requirements+.
+
+ def find_all_by_name(name, *requirements)
+ req = Gem::Requirement.create(*requirements)
+ env_req = Gem.env_requirement(name)
+
+ matches = stubs_for(name).find_all do |spec|
+ req.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
+ end.map(&:to_spec)
+
+ if name == "bundler" && !req.specific?
+ require_relative "bundler_version_finder"
+ Gem::BundlerVersionFinder.prioritize!(matches)
+ end
+
+ matches
+ end
+
+ ##
+ # Return the best specification in the record that contains the file matching +path+.
+
+ def find_by_path(path)
+ path = path.dup.freeze
+ spec = @spec_with_requirable_file[path] ||= stubs.find do |s|
+ s.contains_requirable_file? path
+ end || NOT_FOUND
+
+ spec.to_spec
+ end
+
+ ##
+ # Return the best specification in the record that contains the file
+ # matching +path+ amongst the specs that are not activated.
+
+ def find_inactive_by_path(path)
+ stub = stubs.find do |s|
+ next if s.activated?
+ s.contains_requirable_file? path
+ end
+ stub&.to_spec
+ end
+
+ ##
+ # Return the best specification in the record that contains the file
+ # matching +path+, among those already activated.
+
+ def find_active_stub_by_path(path)
+ stub = @active_stub_with_requirable_file[path] ||= stubs.find do |s|
+ s.activated? && s.contains_requirable_file?(path)
+ end || NOT_FOUND
+
+ stub.this
+ end
+
+ ##
+ # Return the latest specs in the record, optionally including prerelease
+ # specs if +prerelease+ is true.
+
+ def latest_specs(prerelease)
+ Gem::Specification._latest_specs stubs, prerelease
+ end
+
+ ##
+ # Return the latest installed spec in the record for gem +name+.
+
+ def latest_spec_for(name)
+ latest_specs(true).find {|installed_spec| installed_spec.name == name }
+ end
+
+ private
+
+ def installed_stubs(pattern)
+ map_stubs(pattern) do |path, base_dir, gems_dir|
+ Gem::StubSpecification.gemspec_stub(path, base_dir, gems_dir)
+ end
+ end
+
+ def map_stubs(pattern)
+ @dirs.flat_map do |dir|
+ base_dir = File.dirname dir
+ gems_dir = File.join base_dir, "gems"
+ Gem::Specification.gemspec_stubs_in(dir, pattern) {|path| yield path, base_dir, gems_dir }
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb
index c96df2a085..4d72f6fd0a 100644
--- a/lib/rubygems/uninstaller.rb
+++ b/lib/rubygems/uninstaller.rb
@@ -32,7 +32,7 @@ class Gem::Uninstaller
attr_reader :bin_dir
##
- # The gem repository the gem will be installed into
+ # The gem repository the gem will be uninstalled from
attr_reader :gem_home
@@ -49,8 +49,9 @@ class Gem::Uninstaller
# TODO: document the valid options
@gem = gem
@version = options[:version] || Gem::Requirement.default
- @gem_home = File.realpath(options[:install_dir] || Gem.dir)
- @plugins_dir = Gem.plugindir(@gem_home)
+ @install_dir = options[:install_dir]
+ @gem_home = File.realpath(@install_dir || Gem.dir)
+ @user_dir = File.exist?(Gem.user_dir) ? File.realpath(Gem.user_dir) : Gem.user_dir
@force_executables = options[:executables]
@force_all = options[:all]
@force_ignore = options[:ignore]
@@ -70,7 +71,7 @@ class Gem::Uninstaller
# only add user directory if install_dir is not set
@user_install = false
- @user_install = options[:user_install] unless options[:install_dir]
+ @user_install = options[:user_install] unless @install_dir
# Optimization: populated during #uninstall
@default_specs_matching_uninstall_params = []
@@ -105,7 +106,7 @@ class Gem::Uninstaller
list, other_repo_specs = list.partition do |spec|
@gem_home == spec.base_dir ||
- (@user_install && spec.base_dir == Gem.user_dir)
+ (@user_install && spec.base_dir == @user_dir)
end
list.sort!
@@ -239,7 +240,7 @@ class Gem::Uninstaller
def remove(spec)
unless path_ok?(@gem_home, spec) ||
- (@user_install && path_ok?(Gem.user_dir, spec))
+ (@user_install && path_ok?(@user_dir, spec))
e = Gem::GemNotInHomeException.new \
"Gem '#{spec.full_name}' is not installed in directory #{@gem_home}"
e.spec = spec
@@ -284,17 +285,18 @@ class Gem::Uninstaller
def remove_plugins(spec) # :nodoc:
return if spec.plugins.empty?
- remove_plugins_for(spec, @plugins_dir)
+ remove_plugins_for(spec, plugin_dir_for(spec))
end
##
# Regenerates plugin wrappers after removal.
def regenerate_plugins
- latest = Gem::Specification.latest_spec_for(@spec.name)
+ specification_record = @install_dir ? Gem::SpecificationRecord.from_path(@install_dir) : Gem::Specification.specification_record
+ latest = specification_record.latest_spec_for(@spec.name)
return if latest.nil?
- regenerate_plugins_for(latest, @plugins_dir)
+ regenerate_plugins_for(latest, plugin_dir_for(@spec))
end
##
@@ -406,4 +408,8 @@ class Gem::Uninstaller
say "Gem #{spec.full_name} cannot be uninstalled because it is a default gem"
end
end
+
+ def plugin_dir_for(spec)
+ Gem.plugindir(spec.base_dir)
+ end
end
diff --git a/lib/syntax_suggest/clean_document.rb b/lib/syntax_suggest/clean_document.rb
index 0847a62e27..2790ccae86 100644
--- a/lib/syntax_suggest/clean_document.rb
+++ b/lib/syntax_suggest/clean_document.rb
@@ -267,7 +267,7 @@ module SyntaxSuggest
groups.each do |lines|
line = lines.first
- # Handle the case of multiple groups in a a row
+ # Handle the case of multiple groups in a row
# if one is already replaced, move on
next if @document[line.index].empty?
diff --git a/lib/time.rb b/lib/time.rb
index 970932a200..b565130b50 100644
--- a/lib/time.rb
+++ b/lib/time.rb
@@ -391,6 +391,8 @@ class Time
# heuristic to detect the format of the input string, you provide
# a second argument that describes the format of the string.
#
+ # Raises `ArgumentError` if the date or format is invalid.
+ #
# If a block is given, the year described in +date+ is converted by the
# block. For example:
#
diff --git a/load.c b/load.c
index dcf50f5b7a..37f7248b7d 100644
--- a/load.c
+++ b/load.c
@@ -762,11 +762,13 @@ load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
}
else {
rb_ast_t *ast;
+ VALUE ast_value;
VALUE parser = rb_parser_new();
rb_parser_set_context(parser, NULL, FALSE);
- ast = (rb_ast_t *)rb_parser_load_file(parser, fname);
+ ast_value = rb_parser_load_file(parser, fname);
+ ast = rb_ruby_ast_data_get(ast_value);
- iseq = rb_iseq_new_top(&ast->body, rb_fstring_lit("<top (required)>"),
+ iseq = rb_iseq_new_top(ast_value, rb_fstring_lit("<top (required)>"),
fname, realpath_internal_cached(realpath_map, fname), NULL);
rb_ast_dispose(ast);
}
diff --git a/man/ruby.1 b/man/ruby.1
index a0cda14641..bbad8ae203 100644
--- a/man/ruby.1
+++ b/man/ruby.1
@@ -448,18 +448,20 @@ Check syntax (same as
.El
.Pp
Or one of the following, which are intended for debugging the interpreter:
-.Bl -hang -offset indent -tag -width "parsetree_with_comment"
+.Bl -hang -offset indent -tag -width "+error-tolerant"
.It Sy yydebug
Enable compiler debug mode (same as
.Fl -yydebug).
.It Sy parsetree
Print a textual representation of the Ruby AST for the program.
-.It Sy parsetree_with_comment
-Print a textual representation of the Ruby AST for the program, but with each node annotated with the associated Ruby source code.
.It Sy insns
Print a list of disassembled bytecode instructions.
-.It Sy insns_without_opt
-Print the list of disassembled bytecode instructions before various optimizations have been applied.
+.It Sy -optimize
+Disable various optimizations to print a list disassembled bytecode instructions.
+.It Sy +error-tolerant
+Enable error-tolerant parsing, when yydebug or parsetree.
+.It Sy +comment
+Annotate a textual representation of the Ruby AST for the program with the associated Ruby source code.
.El
.Pp
.It Fl -verbose
@@ -537,7 +539,7 @@ malloc family of C standard library calls (
.Xr calloc 3 ,
and
.Xr realloc 3 ) .
-In this documentatation, the "heap" refers to the Ruby object heap
+In this documentation, the "heap" refers to the Ruby object heap
of fixed-sized slots, while "malloc" refers to auxiliary
allocations commonly referred to as the "process heap".
Thus there are at least two possible ways to trigger GC:
diff --git a/marshal.c b/marshal.c
index e26c600ca2..83134371fa 100644
--- a/marshal.c
+++ b/marshal.c
@@ -1696,6 +1696,11 @@ r_copy_ivar(VALUE v, VALUE data)
return v;
}
+#define override_ivar_error(type, str) \
+ rb_raise(rb_eTypeError, \
+ "can't override instance variable of "type" '%"PRIsVALUE"'", \
+ (str))
+
static void
r_ivar(VALUE obj, int *has_encoding, struct load_arg *arg)
{
@@ -1703,6 +1708,12 @@ r_ivar(VALUE obj, int *has_encoding, struct load_arg *arg)
len = r_long(arg);
if (len > 0) {
+ if (RB_TYPE_P(obj, T_MODULE)) {
+ override_ivar_error("module", rb_mod_name(obj));
+ }
+ else if (RB_TYPE_P(obj, T_CLASS)) {
+ override_ivar_error("class", rb_class_name(obj));
+ }
do {
VALUE sym = r_symbol(arg);
VALUE val = r_object(arg);
@@ -1795,9 +1806,7 @@ append_extmod(VALUE obj, VALUE extmod)
#define prohibit_ivar(type, str) do { \
if (!ivp || !*ivp) break; \
- rb_raise(rb_eTypeError, \
- "can't override instance variable of "type" '%"PRIsVALUE"'", \
- (str)); \
+ override_ivar_error(type, str); \
} while (0)
static VALUE r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type);
diff --git a/mini_builtin.c b/mini_builtin.c
index 38b0ca8d81..810125fa2e 100644
--- a/mini_builtin.c
+++ b/mini_builtin.c
@@ -12,16 +12,17 @@
static struct st_table *loaded_builtin_table;
#endif
-rb_ast_t *rb_builtin_ast(const char *feature_name, VALUE *name_str);
+VALUE rb_builtin_ast_value(const char *feature_name, VALUE *name_str);
static const rb_iseq_t *
builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *table)
{
VALUE name_str = 0;
- rb_ast_t *ast = rb_builtin_ast(feature_name, &name_str);
+ rb_ast_t *ast;
+ VALUE ast_value = rb_builtin_ast_value(feature_name, &name_str);
rb_vm_t *vm = GET_VM();
- if (!ast) {
+ if (NIL_P(ast_value)) {
rb_fatal("builtin_iseq_load: can not find %s; "
"probably miniprelude.c is out of date",
feature_name);
@@ -39,7 +40,8 @@ builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *ta
.coverage_enabled = FALSE,
.debug_level = 0,
};
- const rb_iseq_t *iseq = rb_iseq_new_with_opt(&ast->body, name_str, name_str, Qnil, 0, NULL, 0, ISEQ_TYPE_TOP, &optimization, Qnil);
+ ast = rb_ruby_ast_data_get(ast_value);
+ const rb_iseq_t *iseq = rb_iseq_new_with_opt(ast_value, name_str, name_str, Qnil, 0, NULL, 0, ISEQ_TYPE_TOP, &optimization, Qnil);
GET_VM()->builtin_function_table = NULL;
rb_ast_dispose(ast);
diff --git a/misc/lldb_rb/utils.py b/misc/lldb_rb/utils.py
index 86b5bdda2d..1b0e4f9f2a 100644
--- a/misc/lldb_rb/utils.py
+++ b/misc/lldb_rb/utils.py
@@ -60,6 +60,9 @@ class RbInspector(LLDBInterface):
rbUndef = self.ruby_globals["RUBY_Qundef"]
rbImmediateMask = self.ruby_globals["RUBY_IMMEDIATE_MASK"]
+ if self.inspect_node(val):
+ return
+
num = val.GetValueAsSigned()
if num == rbFalse:
print('false', file=self.result)
@@ -245,227 +248,6 @@ class RbInspector(LLDBInterface):
print("T_DATA:", file=self.result)
self._append_expression("*(struct RData *) %0#x" % val.GetValueAsUnsigned())
- elif rval.is_type("RUBY_T_NODE"):
- tRNode = self.target.FindFirstType("struct RNode").GetPointerType()
- rbNodeTypeMask = self.ruby_globals["RUBY_NODE_TYPEMASK"]
- rbNodeTypeShift = self.ruby_globals["RUBY_NODE_TYPESHIFT"]
-
- nd_type = (rval.flags & rbNodeTypeMask) >> rbNodeTypeShift
- val = val.Cast(tRNode)
-
- self._append_expression("(node_type) %d" % nd_type)
-
- if nd_type == self.ruby_globals["NODE_SCOPE"]:
- self._append_expression("*(struct RNode_SCOPE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BLOCK"]:
- self._append_expression("*(struct RNode_BLOCK *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_IF"]:
- self._append_expression("*(struct RNode_IF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_UNLESS"]:
- self._append_expression("*(struct RNode_UNLESS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CASE"]:
- self._append_expression("*(struct RNode_CASE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CASE2"]:
- self._append_expression("*(struct RNode_CASE2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CASE3"]:
- self._append_expression("*(struct RNode_CASE3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_WHEN"]:
- self._append_expression("*(struct RNode_WHEN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_IN"]:
- self._append_expression("*(struct RNode_IN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_WHILE"]:
- self._append_expression("*(struct RNode_WHILE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_UNTIL"]:
- self._append_expression("*(struct RNode_UNTIL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ITER"]:
- self._append_expression("*(struct RNode_ITER *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FOR"]:
- self._append_expression("*(struct RNode_FOR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FOR_MASGN"]:
- self._append_expression("*(struct RNode_FOR_MASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BREAK"]:
- self._append_expression("*(struct RNode_BREAK *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_NEXT"]:
- self._append_expression("*(struct RNode_NEXT *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_REDO"]:
- self._append_expression("*(struct RNode_REDO *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RETRY"]:
- self._append_expression("*(struct RNode_RETRY *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BEGIN"]:
- self._append_expression("*(struct RNode_BEGIN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RESCUE"]:
- self._append_expression("*(struct RNode_RESCUE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RESBODY"]:
- self._append_expression("*(struct RNode_RESBODY *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ENSURE"]:
- self._append_expression("*(struct RNode_ENSURE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_AND"]:
- self._append_expression("*(struct RNode_AND *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OR"]:
- self._append_expression("*(struct RNode_OR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MASGN"]:
- self._append_expression("*(struct RNode_MASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LASGN"]:
- self._append_expression("*(struct RNode_LASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DASGN"]:
- self._append_expression("*(struct RNode_DASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_GASGN"]:
- self._append_expression("*(struct RNode_GASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_IASGN"]:
- self._append_expression("*(struct RNode_IASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CDECL"]:
- self._append_expression("*(struct RNode_CDECL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CVASGN"]:
- self._append_expression("*(struct RNode_CVASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN1"]:
- self._append_expression("*(struct RNode_OP_ASGN1 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN2"]:
- self._append_expression("*(struct RNode_OP_ASGN2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN_AND"]:
- self._append_expression("*(struct RNode_OP_ASGN_AND *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN_OR"]:
- self._append_expression("*(struct RNode_OP_ASGN_OR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_CDECL"]:
- self._append_expression("*(struct RNode_OP_CDECL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CALL"]:
- self._append_expression("*(struct RNode_CALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OPCALL"]:
- self._append_expression("*(struct RNode_OPCALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FCALL"]:
- self._append_expression("*(struct RNode_FCALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_VCALL"]:
- self._append_expression("*(struct RNode_VCALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_QCALL"]:
- self._append_expression("*(struct RNode_QCALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SUPER"]:
- self._append_expression("*(struct RNode_SUPER *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ZSUPER"]:
- self._append_expression("*(struct RNode_ZSUPER *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LIST"]:
- self._append_expression("*(struct RNode_LIST *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ZLIST"]:
- self._append_expression("*(struct RNode_ZLIST *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_HASH"]:
- self._append_expression("*(struct RNode_HASH *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RETURN"]:
- self._append_expression("*(struct RNode_RETURN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_YIELD"]:
- self._append_expression("*(struct RNode_YIELD *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LVAR"]:
- self._append_expression("*(struct RNode_LVAR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DVAR"]:
- self._append_expression("*(struct RNode_DVAR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_GVAR"]:
- self._append_expression("*(struct RNode_GVAR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CONST"]:
- self._append_expression("*(struct RNode_CONST *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CVAR"]:
- self._append_expression("*(struct RNode_CVAR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_NTH_REF"]:
- self._append_expression("*(struct RNode_NTH_REF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BACK_REF"]:
- self._append_expression("*(struct RNode_BACK_REF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MATCH"]:
- self._append_expression("*(struct RNode_MATCH *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MATCH2"]:
- self._append_expression("*(struct RNode_MATCH2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MATCH3"]:
- self._append_expression("*(struct RNode_MATCH3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_STR"]:
- self._append_expression("*(struct RNode_STR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DSTR"]:
- self._append_expression("*(struct RNode_DSTR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_XSTR"]:
- self._append_expression("*(struct RNode_XSTR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DXSTR"]:
- self._append_expression("*(struct RNode_DXSTR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_EVSTR"]:
- self._append_expression("*(struct RNode_EVSTR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_REGX"]:
- self._append_expression("*(struct RNode_REGX *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DREGX"]:
- self._append_expression("*(struct RNode_DREGX *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ONCE"]:
- self._append_expression("*(struct RNode_ONCE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGS"]:
- self._append_expression("*(struct RNode_ARGS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGS_AUX"]:
- self._append_expression("*(struct RNode_ARGS_AUX *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OPT_ARG"]:
- self._append_expression("*(struct RNode_OPT_ARG *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_KW_ARG"]:
- self._append_expression("*(struct RNode_KW_ARG *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_POSTARG"]:
- self._append_expression("*(struct RNode_POSTARG *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGSCAT"]:
- self._append_expression("*(struct RNode_ARGSCAT *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGSPUSH"]:
- self._append_expression("*(struct RNode_ARGSPUSH *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SPLAT"]:
- self._append_expression("*(struct RNode_SPLAT *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DEFN"]:
- self._append_expression("*(struct RNode_DEFN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DEFS"]:
- self._append_expression("*(struct RNode_DEFS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ALIAS"]:
- self._append_expression("*(struct RNode_ALIAS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_VALIAS"]:
- self._append_expression("*(struct RNode_VALIAS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_UNDEF"]:
- self._append_expression("*(struct RNode_UNDEF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CLASS"]:
- self._append_expression("*(struct RNode_CLASS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MODULE"]:
- self._append_expression("*(struct RNode_MODULE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SCLASS"]:
- self._append_expression("*(struct RNode_SCLASS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_COLON2"]:
- self._append_expression("*(struct RNode_COLON2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_COLON3"]:
- self._append_expression("*(struct RNode_COLON3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DOT2"]:
- self._append_expression("*(struct RNode_DOT2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DOT3"]:
- self._append_expression("*(struct RNode_DOT3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FLIP2"]:
- self._append_expression("*(struct RNode_FLIP2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FLIP3"]:
- self._append_expression("*(struct RNode_FLIP3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SELF"]:
- self._append_expression("*(struct RNode_SELF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_NIL"]:
- self._append_expression("*(struct RNode_NIL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_TRUE"]:
- self._append_expression("*(struct RNode_TRUE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FALSE"]:
- self._append_expression("*(struct RNode_FALSE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ERRINFO"]:
- self._append_expression("*(struct RNode_ERRINFO *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DEFINED"]:
- self._append_expression("*(struct RNode_DEFINED *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_POSTEXE"]:
- self._append_expression("*(struct RNode_POSTEXE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DSYM"]:
- self._append_expression("*(struct RNode_DSYM *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ATTRASGN"]:
- self._append_expression("*(struct RNode_ATTRASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LAMBDA"]:
- self._append_expression("*(struct RNode_LAMBDA *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARYPTN"]:
- self._append_expression("*(struct RNode_ARYPTN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_HSHPTN"]:
- self._append_expression("*(struct RNode_HSHPTN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FNDPTN"]:
- self._append_expression("*(struct RNode_FNDPTN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ERROR"]:
- self._append_expression("*(struct RNode_ERROR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LINE"]:
- self._append_expression("*(struct RNode_LINE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FILE"]:
- self._append_expression("*(struct RNode_FILE *) %0#x" % val.GetValueAsUnsigned())
- else:
- self._append_expression("*(struct RNode *) %0#x" % val.GetValueAsUnsigned())
-
elif rval.is_type("RUBY_T_IMEMO"):
imemo_type = ((rval.flags >> self.ruby_globals["RUBY_FL_USHIFT"])
& IMEMO_MASK)
@@ -492,3 +274,230 @@ class RbInspector(LLDBInterface):
else:
print("Not-handled type %0#x" % rval.type, file=self.result)
print(val, file=self.result)
+
+ def inspect_node(self, val):
+ tRNode = self.target.FindFirstType("struct RNode").GetPointerType()
+
+ # if val.GetType() != tRNode: does not work for unknown reason
+
+ if val.GetType().GetPointeeType().name != "NODE":
+ return False
+
+ rbNodeTypeMask = self.ruby_globals["RUBY_NODE_TYPEMASK"]
+ rbNodeTypeShift = self.ruby_globals["RUBY_NODE_TYPESHIFT"]
+ flags = val.Cast(tRNode).GetChildMemberWithName("flags").GetValueAsUnsigned()
+ nd_type = (flags & rbNodeTypeMask) >> rbNodeTypeShift
+
+ self._append_expression("(node_type) %d" % nd_type)
+
+ if nd_type == self.ruby_globals["NODE_SCOPE"]:
+ self._append_expression("*(struct RNode_SCOPE *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_BLOCK"]:
+ self._append_expression("*(struct RNode_BLOCK *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_IF"]:
+ self._append_expression("*(struct RNode_IF *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_UNLESS"]:
+ self._append_expression("*(struct RNode_UNLESS *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CASE"]:
+ self._append_expression("*(struct RNode_CASE *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CASE2"]:
+ self._append_expression("*(struct RNode_CASE2 *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CASE3"]:
+ self._append_expression("*(struct RNode_CASE3 *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_WHEN"]:
+ self._append_expression("*(struct RNode_WHEN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_IN"]:
+ self._append_expression("*(struct RNode_IN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_WHILE"]:
+ self._append_expression("*(struct RNode_WHILE *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_UNTIL"]:
+ self._append_expression("*(struct RNode_UNTIL *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ITER"]:
+ self._append_expression("*(struct RNode_ITER *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FOR"]:
+ self._append_expression("*(struct RNode_FOR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FOR_MASGN"]:
+ self._append_expression("*(struct RNode_FOR_MASGN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_BREAK"]:
+ self._append_expression("*(struct RNode_BREAK *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_NEXT"]:
+ self._append_expression("*(struct RNode_NEXT *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_REDO"]:
+ self._append_expression("*(struct RNode_REDO *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_RETRY"]:
+ self._append_expression("*(struct RNode_RETRY *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_BEGIN"]:
+ self._append_expression("*(struct RNode_BEGIN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_RESCUE"]:
+ self._append_expression("*(struct RNode_RESCUE *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_RESBODY"]:
+ self._append_expression("*(struct RNode_RESBODY *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ENSURE"]:
+ self._append_expression("*(struct RNode_ENSURE *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_AND"]:
+ self._append_expression("*(struct RNode_AND *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OR"]:
+ self._append_expression("*(struct RNode_OR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_MASGN"]:
+ self._append_expression("*(struct RNode_MASGN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_LASGN"]:
+ self._append_expression("*(struct RNode_LASGN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DASGN"]:
+ self._append_expression("*(struct RNode_DASGN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_GASGN"]:
+ self._append_expression("*(struct RNode_GASGN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_IASGN"]:
+ self._append_expression("*(struct RNode_IASGN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CDECL"]:
+ self._append_expression("*(struct RNode_CDECL *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CVASGN"]:
+ self._append_expression("*(struct RNode_CVASGN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OP_ASGN1"]:
+ self._append_expression("*(struct RNode_OP_ASGN1 *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OP_ASGN2"]:
+ self._append_expression("*(struct RNode_OP_ASGN2 *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OP_ASGN_AND"]:
+ self._append_expression("*(struct RNode_OP_ASGN_AND *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OP_ASGN_OR"]:
+ self._append_expression("*(struct RNode_OP_ASGN_OR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OP_CDECL"]:
+ self._append_expression("*(struct RNode_OP_CDECL *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CALL"]:
+ self._append_expression("*(struct RNode_CALL *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OPCALL"]:
+ self._append_expression("*(struct RNode_OPCALL *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FCALL"]:
+ self._append_expression("*(struct RNode_FCALL *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_VCALL"]:
+ self._append_expression("*(struct RNode_VCALL *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_QCALL"]:
+ self._append_expression("*(struct RNode_QCALL *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_SUPER"]:
+ self._append_expression("*(struct RNode_SUPER *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ZSUPER"]:
+ self._append_expression("*(struct RNode_ZSUPER *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_LIST"]:
+ self._append_expression("*(struct RNode_LIST *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ZLIST"]:
+ self._append_expression("*(struct RNode_ZLIST *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_HASH"]:
+ self._append_expression("*(struct RNode_HASH *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_RETURN"]:
+ self._append_expression("*(struct RNode_RETURN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_YIELD"]:
+ self._append_expression("*(struct RNode_YIELD *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_LVAR"]:
+ self._append_expression("*(struct RNode_LVAR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DVAR"]:
+ self._append_expression("*(struct RNode_DVAR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_GVAR"]:
+ self._append_expression("*(struct RNode_GVAR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CONST"]:
+ self._append_expression("*(struct RNode_CONST *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CVAR"]:
+ self._append_expression("*(struct RNode_CVAR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_NTH_REF"]:
+ self._append_expression("*(struct RNode_NTH_REF *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_BACK_REF"]:
+ self._append_expression("*(struct RNode_BACK_REF *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_MATCH"]:
+ self._append_expression("*(struct RNode_MATCH *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_MATCH2"]:
+ self._append_expression("*(struct RNode_MATCH2 *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_MATCH3"]:
+ self._append_expression("*(struct RNode_MATCH3 *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_STR"]:
+ self._append_expression("*(struct RNode_STR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DSTR"]:
+ self._append_expression("*(struct RNode_DSTR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_XSTR"]:
+ self._append_expression("*(struct RNode_XSTR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DXSTR"]:
+ self._append_expression("*(struct RNode_DXSTR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_EVSTR"]:
+ self._append_expression("*(struct RNode_EVSTR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_REGX"]:
+ self._append_expression("*(struct RNode_REGX *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DREGX"]:
+ self._append_expression("*(struct RNode_DREGX *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ONCE"]:
+ self._append_expression("*(struct RNode_ONCE *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ARGS"]:
+ self._append_expression("*(struct RNode_ARGS *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ARGS_AUX"]:
+ self._append_expression("*(struct RNode_ARGS_AUX *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OPT_ARG"]:
+ self._append_expression("*(struct RNode_OPT_ARG *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_KW_ARG"]:
+ self._append_expression("*(struct RNode_KW_ARG *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_POSTARG"]:
+ self._append_expression("*(struct RNode_POSTARG *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ARGSCAT"]:
+ self._append_expression("*(struct RNode_ARGSCAT *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ARGSPUSH"]:
+ self._append_expression("*(struct RNode_ARGSPUSH *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_SPLAT"]:
+ self._append_expression("*(struct RNode_SPLAT *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DEFN"]:
+ self._append_expression("*(struct RNode_DEFN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DEFS"]:
+ self._append_expression("*(struct RNode_DEFS *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ALIAS"]:
+ self._append_expression("*(struct RNode_ALIAS *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_VALIAS"]:
+ self._append_expression("*(struct RNode_VALIAS *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_UNDEF"]:
+ self._append_expression("*(struct RNode_UNDEF *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CLASS"]:
+ self._append_expression("*(struct RNode_CLASS *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_MODULE"]:
+ self._append_expression("*(struct RNode_MODULE *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_SCLASS"]:
+ self._append_expression("*(struct RNode_SCLASS *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_COLON2"]:
+ self._append_expression("*(struct RNode_COLON2 *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_COLON3"]:
+ self._append_expression("*(struct RNode_COLON3 *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DOT2"]:
+ self._append_expression("*(struct RNode_DOT2 *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DOT3"]:
+ self._append_expression("*(struct RNode_DOT3 *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FLIP2"]:
+ self._append_expression("*(struct RNode_FLIP2 *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FLIP3"]:
+ self._append_expression("*(struct RNode_FLIP3 *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_SELF"]:
+ self._append_expression("*(struct RNode_SELF *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_NIL"]:
+ self._append_expression("*(struct RNode_NIL *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_TRUE"]:
+ self._append_expression("*(struct RNode_TRUE *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FALSE"]:
+ self._append_expression("*(struct RNode_FALSE *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ERRINFO"]:
+ self._append_expression("*(struct RNode_ERRINFO *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DEFINED"]:
+ self._append_expression("*(struct RNode_DEFINED *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_POSTEXE"]:
+ self._append_expression("*(struct RNode_POSTEXE *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DSYM"]:
+ self._append_expression("*(struct RNode_DSYM *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ATTRASGN"]:
+ self._append_expression("*(struct RNode_ATTRASGN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_LAMBDA"]:
+ self._append_expression("*(struct RNode_LAMBDA *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ARYPTN"]:
+ self._append_expression("*(struct RNode_ARYPTN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_HSHPTN"]:
+ self._append_expression("*(struct RNode_HSHPTN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FNDPTN"]:
+ self._append_expression("*(struct RNode_FNDPTN *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ERROR"]:
+ self._append_expression("*(struct RNode_ERROR *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_LINE"]:
+ self._append_expression("*(struct RNode_LINE *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FILE"]:
+ self._append_expression("*(struct RNode_FILE *) %0#x" % val.GetValueAsUnsigned())
+ else:
+ self._append_expression("*(struct RNode *) %0#x" % val.GetValueAsUnsigned())
+ return True
diff --git a/missing/setproctitle.c b/missing/setproctitle.c
index f90886671c..5b2dfa65ce 100644
--- a/missing/setproctitle.c
+++ b/missing/setproctitle.c
@@ -87,7 +87,30 @@ static char **argv1_addr = NULL;
#endif
#if ALLOCATE_ENVIRON
+/* system_environ is the value of environ before we allocate a custom buffer.
+ *
+ * We use this to restore environ in ruby_free_proctitle.
+ */
+static char **system_environ = NULL;
+/* orig_environ is the buffer we allocate for environ.
+ *
+ * We use this to free this buffer in ruby_free_proctitle. When we add new
+ * environment variables using setenv, the system may change environ to a
+ * different buffer and will not free the original buffer, so we need to hold
+ * onto this so we can free it in ruby_free_proctitle.
+ *
+ * We must not free any of the contents because it may change if the system
+ * updates existing environment variables.
+ */
static char **orig_environ = NULL;
+/* alloc_environ is a copy of orig_environ.
+ *
+ * We use this to free all the original string copies that were in orig_environ.
+ * Since environ could be changed to point to strings allocated by the system
+ * if environment variables are updated, so we need this to point to the
+ * original strings.
+ */
+static char **alloc_environ = NULL;
#endif
void
@@ -112,6 +135,9 @@ compat_init_setproctitle(int argc, char *argv[])
/* Fail if we can't allocate room for the new environment */
for (i = 0; envp[i] != NULL; i++);
+ system_environ = environ;
+
+ alloc_environ = xcalloc(i + 1, sizeof(*environ));
orig_environ = environ = xcalloc(i + 1, sizeof(*environ));
if (environ == NULL) {
environ = envp; /* put it back */
@@ -140,8 +166,8 @@ compat_init_setproctitle(int argc, char *argv[])
argv_env_len = lastenvp - argv[0];
for (i = 0; envp[i] != NULL; i++)
- environ[i] = ruby_strdup(envp[i]);
- environ[i] = NULL;
+ alloc_environ[i] = environ[i] = ruby_strdup(envp[i]);
+ alloc_environ[i] = environ[i] = NULL;
#endif /* SPT_REUSEARGV */
}
@@ -153,16 +179,13 @@ ruby_free_proctitle(void)
if (!orig_environ) return; /* environ is allocated by OS */
- /* ruby_setenv could allocate a new environ, so we need to free orig_environ
- * in that case. */
- if (environ != orig_environ) {
- for (int i = 0; orig_environ[i] != NULL; i++) {
- xfree(orig_environ[i]);
- }
-
- xfree(orig_environ);
- orig_environ = NULL;
+ for (int i = 0; alloc_environ[i] != NULL; i++) {
+ xfree(alloc_environ[i]);
}
+ xfree(alloc_environ);
+ xfree(orig_environ);
+
+ environ = system_environ;
#endif
}
diff --git a/node.c b/node.c
index 7706f71fda..2efcd6eba8 100644
--- a/node.c
+++ b/node.c
@@ -10,19 +10,9 @@
**********************************************************************/
#ifdef UNIVERSAL_PARSER
-
#include <stddef.h>
#include "node.h"
#include "rubyparser.h"
-#include "internal/parse.h"
-
-#else
-
-#include "internal.h"
-#include "internal/hash.h"
-#include "ruby/ruby.h"
-#include "vm_core.h"
-
#endif
#include "internal/variable.h"
@@ -68,19 +58,16 @@ rb_node_buffer_new(void)
init_node_buffer_list(&nb->buffer_list, (node_buffer_elem_t*)&nb[1], ruby_xmalloc);
nb->local_tables = 0;
nb->tokens = 0;
-#ifdef UNIVERSAL_PARSER
- nb->config = config;
-#endif
return nb;
}
#ifdef UNIVERSAL_PARSER
#undef ruby_xmalloc
-#define ruby_xmalloc ast->node_buffer->config->malloc
+#define ruby_xmalloc ast->config->malloc
#undef xfree
-#define xfree ast->node_buffer->config->free
-#define rb_xmalloc_mul_add ast->node_buffer->config->xmalloc_mul_add
-#define ruby_xrealloc(var,size) (ast->node_buffer->config->realloc_n((void *)var, 1, size))
+#define xfree ast->config->free
+#define rb_xmalloc_mul_add ast->config->xmalloc_mul_add
+#define ruby_xrealloc(var,size) (ast->config->realloc_n((void *)var, 1, size))
#endif
typedef void node_itr_t(rb_ast_t *ast, void *ctx, NODE *node);
@@ -227,8 +214,8 @@ free_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
static void
rb_node_buffer_free(rb_ast_t *ast, node_buffer_t *nb)
{
- if (ast->node_buffer && ast->node_buffer->tokens) {
- parser_tokens_free(ast, ast->node_buffer->tokens);
+ if (nb && nb->tokens) {
+ parser_tokens_free(ast, nb->tokens);
}
iterate_node_values(ast, &nb->buffer_list, free_ast_value, NULL);
node_buffer_list_free(ast, &nb->buffer_list);
@@ -313,14 +300,19 @@ rb_ast_t *
rb_ast_new(const rb_parser_config_t *config)
{
node_buffer_t *nb = rb_node_buffer_new(config);
- return config->ast_new((VALUE)nb);
+ rb_ast_t *ast = (rb_ast_t *)config->calloc(1, sizeof(rb_ast_t));
+ ast->config = config;
+ ast->node_buffer = nb;
+ return ast;
}
#else
rb_ast_t *
rb_ast_new(void)
{
node_buffer_t *nb = rb_node_buffer_new();
- return IMEMO_NEW(rb_ast_t, imemo_ast, (VALUE)nb);
+ rb_ast_t *ast = ruby_xcalloc(1, sizeof(rb_ast_t));
+ ast->node_buffer = nb;
+ return ast;
}
#endif
@@ -347,6 +339,7 @@ iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_t * func, vo
static void
script_lines_free(rb_ast_t *ast, rb_parser_ary_t *script_lines)
{
+ if (!script_lines) return;
for (long i = 0; i < script_lines->len; i++) {
parser_string_free(ast, (rb_parser_string_t *)script_lines->data[i]);
}
@@ -357,14 +350,8 @@ script_lines_free(rb_ast_t *ast, rb_parser_ary_t *script_lines)
void
rb_ast_free(rb_ast_t *ast)
{
- if (ast->node_buffer) {
- if (ast->body.script_lines && !FIXNUM_P((VALUE)ast->body.script_lines)) {
- script_lines_free(ast, ast->body.script_lines);
- ast->body.script_lines = NULL;
- }
- rb_node_buffer_free(ast, ast->node_buffer);
- ast->node_buffer = 0;
- }
+ rb_ast_dispose(ast);
+ xfree(ast);
}
static size_t
@@ -382,20 +369,57 @@ buffer_list_size(node_buffer_list_t *nb)
size_t
rb_ast_memsize(const rb_ast_t *ast)
{
- size_t size = 0;
+ size_t size = sizeof(rb_ast_t);
node_buffer_t *nb = ast->node_buffer;
+ rb_parser_ary_t *tokens = NULL;
+ struct rb_ast_local_table_link *link = NULL;
+ rb_parser_ary_t *script_lines = ast->body.script_lines;
+
+ long i;
if (nb) {
size += sizeof(node_buffer_t);
size += buffer_list_size(&nb->buffer_list);
+ link = nb->local_tables;
+ tokens = nb->tokens;
}
+
+ while (link) {
+ size += sizeof(struct rb_ast_local_table_link);
+ size += link->size * sizeof(ID);
+ link = link->next;
+ }
+
+ if (tokens) {
+ size += sizeof(rb_parser_ary_t);
+ for (i = 0; i < tokens->len; i++) {
+ size += sizeof(rb_parser_ast_token_t);
+ rb_parser_ast_token_t *token = tokens->data[i];
+ size += sizeof(rb_parser_string_t);
+ size += token->str->len + 1;
+ }
+ }
+
+ if (script_lines) {
+ size += sizeof(rb_parser_ary_t);
+ for (i = 0; i < script_lines->len; i++) {
+ size += sizeof(rb_parser_string_t);
+ size += ((rb_parser_string_t *)script_lines->data[i])->len + 1;
+ }
+ }
+
return size;
}
void
rb_ast_dispose(rb_ast_t *ast)
{
- rb_ast_free(ast);
+ if (ast && ast->node_buffer) {
+ script_lines_free(ast, ast->body.script_lines);
+ ast->body.script_lines = NULL;
+ rb_node_buffer_free(ast, ast->node_buffer);
+ ast->node_buffer = 0;
+ }
}
VALUE
diff --git a/node.h b/node.h
index bcc7e451d2..1e411f211b 100644
--- a/node.h
+++ b/node.h
@@ -39,9 +39,6 @@ struct node_buffer_struct {
// - location info
// Array, whose entry is array
rb_parser_ary_t *tokens;
-#ifdef UNIVERSAL_PARSER
- const rb_parser_config_t *config;
-#endif
};
RUBY_SYMBOL_EXPORT_BEGIN
@@ -88,6 +85,7 @@ RUBY_SYMBOL_EXPORT_END
#define NODE_SPECIAL_EXCESSIVE_COMMA ((ID)1)
#define NODE_SPECIAL_NO_REST_KEYWORD ((NODE *)-1)
+#define nd_code_loc(n) (&RNODE(n)->nd_loc)
#define nd_first_column(n) ((int)(RNODE(n)->nd_loc.beg_pos.column))
#define nd_set_first_column(n, v) (RNODE(n)->nd_loc.beg_pos.column = (v))
#define nd_first_lineno(n) ((int)(RNODE(n)->nd_loc.beg_pos.lineno))
diff --git a/numeric.c b/numeric.c
index f613d4120d..4db0834ae3 100644
--- a/numeric.c
+++ b/numeric.c
@@ -862,6 +862,8 @@ rb_int_zero_p(VALUE num)
* Of the Core and Standard Library classes,
* Integer, Float, Rational, and Complex use this implementation.
*
+ * Related: #zero?
+ *
*/
static VALUE
diff --git a/object.c b/object.c
index 54240f0774..0a8ce4dc0f 100644
--- a/object.c
+++ b/object.c
@@ -3236,15 +3236,22 @@ ALWAYS_INLINE(static VALUE rb_to_integer_with_id_exception(VALUE val, const char
static inline VALUE
rb_to_integer_with_id_exception(VALUE val, const char *method, ID mid, int raise)
{
+ // We need to pop the lazily pushed frame when not raising an exception.
+ rb_control_frame_t *current_cfp;
VALUE v;
if (RB_INTEGER_TYPE_P(val)) return val;
+ current_cfp = GET_EC()->cfp;
rb_yjit_lazy_push_frame(GET_EC()->cfp->pc);
v = try_to_int(val, mid, raise);
- if (!raise && NIL_P(v)) return Qnil;
+ if (!raise && NIL_P(v)) {
+ GET_EC()->cfp = current_cfp;
+ return Qnil;
+ }
if (!RB_INTEGER_TYPE_P(v)) {
conversion_mismatch(val, "Integer", method, v);
}
+ GET_EC()->cfp = current_cfp;
return v;
}
#define rb_to_integer(val, method, mid) \
diff --git a/parse.y b/parse.y
index a87be73e3c..5fe9babefa 100644
--- a/parse.y
+++ b/parse.y
@@ -81,14 +81,10 @@ syntax_error_new(void)
static NODE *reg_named_capture_assign(struct parser_params* p, VALUE regexp, const YYLTYPE *loc);
#define compile_callback rb_suppress_tracing
-VALUE rb_io_gets_internal(VALUE io);
#endif /* !UNIVERSAL_PARSER */
static int rb_parser_string_hash_cmp(rb_parser_string_t *str1, rb_parser_string_t *str2);
-
-#ifndef RIPPER
static rb_parser_string_t *rb_parser_string_deep_copy(struct parser_params *p, const rb_parser_string_t *original);
-#endif
static int
node_integer_cmp(rb_node_integer_t *n1, rb_node_integer_t *n2)
@@ -490,8 +486,8 @@ struct parser_params {
struct {
rb_strterm_t *strterm;
- VALUE (*gets)(struct parser_params*,VALUE);
- VALUE input;
+ rb_parser_lex_gets_func *gets;
+ rb_parser_input_data input;
parser_string_buffer_t string_buffer;
rb_parser_string_t *lastline;
rb_parser_string_t *nextline;
@@ -499,10 +495,6 @@ struct parser_params {
const char *pcur;
const char *pend;
const char *ptok;
- union {
- long ptr;
- VALUE (*call)(VALUE, int);
- } gets_;
enum lex_state_e state;
/* track the nest level of any parens "()[]{}" */
int paren_nest;
@@ -525,7 +517,7 @@ struct parser_params {
int line_count;
int ruby_sourceline; /* current line no. */
const char *ruby_sourcefile; /* current source file */
- VALUE ruby_sourcefile_string;
+ rb_parser_string_t *ruby_sourcefile_string;
rb_encoding *enc;
token_info *token_info;
st_table *case_labels;
@@ -1166,7 +1158,7 @@ static rb_node_aryptn_t *rb_node_aryptn_new(struct parser_params *p, NODE *pre_a
static rb_node_hshptn_t *rb_node_hshptn_new(struct parser_params *p, NODE *nd_pconst, NODE *nd_pkwargs, NODE *nd_pkwrestarg, const YYLTYPE *loc);
static rb_node_fndptn_t *rb_node_fndptn_new(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc);
static rb_node_line_t *rb_node_line_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_file_t *rb_node_file_new(struct parser_params *p, VALUE str, const YYLTYPE *loc);
+static rb_node_file_t *rb_node_file_new(struct parser_params *p, rb_parser_string_t *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)
@@ -1775,9 +1767,6 @@ endless_method_name(struct parser_params *p, ID mid, const YYLTYPE *loc)
local_push(p, 0); \
} while (0)
-#define Qnone 0
-#define Qnull 0
-
#ifndef RIPPER
# define ifndef_ripper(x) (x)
#else
@@ -2111,6 +2100,41 @@ rb_parser_encoding_string_new(rb_parser_t *p, const char *ptr, long len, rb_enco
}
#ifndef RIPPER
+static bool
+zero_filled(const char *s, int n)
+{
+ for (; n > 0; --n) {
+ if (*s++) return false;
+ }
+ return true;
+}
+
+static bool
+str_null_char(rb_parser_t *p, const char *s, long len, const int minlen, rb_encoding *enc)
+{
+ const char *e = s + len;
+
+ for (; s + minlen <= e; s += rb_enc_mbclen(s, e, enc)) {
+ if (zero_filled(s, minlen)) return true;
+ }
+ return false;
+}
+
+static bool
+cstr_null_check(rb_parser_t *p, const char *s, long len, rb_encoding *enc, int *w)
+{
+ const int minlen = rb_enc_mbminlen(enc);
+
+ if (minlen > 1) {
+ *w = 1;
+ return str_null_char(p, s, len, minlen, enc);
+ }
+ else {
+ *w = 0;
+ return (!s || memchr(s, 0, len));
+ }
+}
+
rb_parser_string_t *
rb_str_to_parser_string(rb_parser_t *p, VALUE str)
{
@@ -2830,22 +2854,19 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%type <node> if_tail opt_else case_body case_args cases opt_rescue exc_list exc_var opt_ensure
%type <node> args arg_splat call_args opt_call_args
%type <node> paren_args opt_paren_args
-%type <node_args> args_tail opt_args_tail block_args_tail opt_block_args_tail
+%type <node_args> args_tail block_args_tail
%type <node> command_args aref_args
%type <node_block_pass> opt_block_arg block_arg
%type <node> var_ref var_lhs
%type <node> command_rhs arg_rhs
%type <node> command_asgn mrhs mrhs_arg superclass block_call block_command
-%type <node_opt_arg> f_block_optarg f_block_opt
%type <node_args> f_arglist f_opt_paren_args f_paren_args f_args
%type <node_args_aux> f_arg f_arg_item
-%type <node_opt_arg> f_optarg
%type <node> f_marg f_marg_list f_rest_marg
%type <node_masgn> f_margs
%type <node> assoc_list assocs assoc undef_list backref string_dvar for_var
%type <node_args> block_param opt_block_param block_param_def
-%type <node_opt_arg> f_opt
-%type <node_kw_arg> f_kwarg f_kw f_block_kwarg f_block_kw
+%type <node_kw_arg> f_kw f_block_kw
%type <id> bv_decls opt_bv_decl bvar
%type <node> lambda lambda_body brace_body do_body
%type <node_args> f_larglist
@@ -2959,6 +2980,61 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%token tLAST_TOKEN
+/*
+ * parameterizing rules
+ */
+%rule f_opt(value) <node_opt_arg>: f_arg_asgn f_eq value
+ {
+ p->cur_arg = 0;
+ p->ctxt.in_argdef = 1;
+ $$ = NEW_OPT_ARG(assignable(p, $1, $3, &@$), &@$);
+ /*% ripper: rb_assoc_new(ripper_assignable(p, $1, get_value($:1)), get_value($:3)) %*/
+ }
+ ;
+
+%rule f_optarg(value) <node_opt_arg>: f_opt(value)
+ {
+ $$ = $1;
+ /*% ripper: rb_ary_new3(1, get_value($:1)) %*/
+ }
+ | f_optarg(value) ',' f_opt(value)
+ {
+ $$ = opt_arg_append($1, $3);
+ /*% ripper: rb_ary_push(get_value($:1), get_value($:3)) %*/
+ }
+ ;
+
+%rule f_kwarg(kw) <node_kw_arg>: kw
+ {
+ $$ = $1;
+ /*% ripper: rb_ary_new3(1, get_value($:1)) %*/
+ }
+ | f_kwarg(kw) ',' kw
+ {
+ $$ = kwd_append($1, $3);
+ /*% ripper: rb_ary_push(get_value($:1), get_value($:3)) %*/
+ }
+ ;
+
+%rule opt_args_tail(tail) <node_args>: ',' tail
+ {
+ $$ = $2;
+ /*% ripper: get_value($:2); %*/
+ }
+ | /* none */
+ {
+ $$ = new_args_tail(p, 0, 0, 0, &@0);
+ /*% ripper: rb_ary_new_from_args(3, Qnil, Qnil, Qnil); %*/
+ }
+ ;
+
+%rule words(begin, word_list): begin ' '+ word_list tSTRING_END
+ {
+ $$ = make_list($3, &@$);
+ /*% ripper: array!($:3) %*/
+ }
+ ;
+
%%
program : {
SET_LEX_STATE(EXPR_BEG);
@@ -3306,7 +3382,7 @@ command_asgn : lhs '=' lex_ctxt command_rhs
rb_backref_error(p, $1);
/*% %*/
$$ = NEW_ERROR(&@$);
- /*% ripper[error]: backref_error(p, RNODE($:1), assign!(var_field(p, get_value($:1)), $:4)) %*/
+ /*% ripper[error]: backref_error(p, $1, opassign!(var_field(p, get_value($:1)), $:2, $:4)) %*/
}
;
@@ -3492,7 +3568,7 @@ command : fcall command_args %prec tLOWEST
}
| primary_value call_op operation2 command_args %prec tLOWEST
{
- $$ = new_command_qcall(p, $2, $1, $3, $4, Qnull, &@3, &@$);
+ $$ = new_command_qcall(p, $2, $1, $3, $4, 0, &@3, &@$);
/*% ripper: command_call!($:1, $:2, $:3, $:4) %*/
}
| primary_value call_op operation2 command_args cmd_brace_block
@@ -3502,7 +3578,7 @@ command : fcall command_args %prec tLOWEST
}
| primary_value tCOLON2 operation2 command_args %prec tLOWEST
{
- $$ = new_command_qcall(p, idCOLON2, $1, $3, $4, Qnull, &@3, &@$);
+ $$ = new_command_qcall(p, idCOLON2, $1, $3, $4, 0, &@3, &@$);
/*% ripper: command_call!($:1, $:2, $:3, $:4) %*/
}
| primary_value tCOLON2 operation2 command_args cmd_brace_block
@@ -3513,7 +3589,7 @@ command : fcall command_args %prec tLOWEST
| primary_value tCOLON2 tCONSTANT '{' brace_body '}'
{
set_embraced_location($5, &@4, &@6);
- $$ = new_command_qcall(p, idCOLON2, $1, $3, Qnull, $5, &@3, &@$);
+ $$ = new_command_qcall(p, idCOLON2, $1, $3, 0, $5, &@3, &@$);
/*% ripper: method_add_block!(command_call!($:1, $:2, $:3, Qnil), $:5) %*/
}
| keyword_super command_args
@@ -3905,7 +3981,7 @@ arg : lhs '=' lex_ctxt arg_rhs
/*%%%*/
$$ = NEW_ERROR(&@$);
/*% %*/
- /*% ripper[error]: backref_error(p, RNODE($:1), opassign!(var_field(p, get_value($:1)), $:2, $:4)) %*/
+ /*% ripper[error]: backref_error(p, $1, opassign!(var_field(p, get_value($:1)), $:2, $:4)) %*/
}
| arg tDOT2 arg
{
@@ -4219,7 +4295,7 @@ paren_args : '(' opt_call_args rparen
| '(' args ',' args_forward rparen
{
if (!check_forwarding_args(p)) {
- $$ = Qnone;
+ $$ = 0;
}
else {
$$ = new_args_forward_call(p, $2, &@4, &@$);
@@ -4229,7 +4305,7 @@ paren_args : '(' opt_call_args rparen
| '(' args_forward rparen
{
if (!check_forwarding_args(p)) {
- $$ = Qnone;
+ $$ = 0;
}
else {
$$ = new_args_forward_call(p, 0, &@2, &@$);
@@ -5027,40 +5103,28 @@ f_any_kwrest : f_kwrest
f_eq : {p->ctxt.in_argdef = 0;} '=';
-block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg
+block_args_tail : f_kwarg(f_block_kw) ',' f_kwrest opt_f_block_arg
{
$$ = new_args_tail(p, $1, $3, $4, &@3);
/*% ripper: rb_ary_new_from_args(3, get_value($:1), get_value($:3), get_value($:4)); %*/
}
- | f_block_kwarg opt_f_block_arg
+ | f_kwarg(f_block_kw) opt_f_block_arg
{
- $$ = new_args_tail(p, $1, Qnone, $2, &@1);
+ $$ = new_args_tail(p, $1, 0, $2, &@1);
/*% ripper: rb_ary_new_from_args(3, get_value($:1), Qnil, get_value($:2)); %*/
}
| f_any_kwrest opt_f_block_arg
{
- $$ = new_args_tail(p, Qnone, $1, $2, &@1);
+ $$ = new_args_tail(p, 0, $1, $2, &@1);
/*% ripper: rb_ary_new_from_args(3, Qnil, get_value($:1), get_value($:2)); %*/
}
| f_block_arg
{
- $$ = new_args_tail(p, Qnone, Qnone, $1, &@1);
+ $$ = new_args_tail(p, 0, 0, $1, &@1);
/*% ripper: rb_ary_new_from_args(3, Qnil, Qnil, get_value($:1)); %*/
}
;
-opt_block_args_tail : ',' block_args_tail
- {
- $$ = $2;
- /*% ripper: get_value($:2); %*/
- }
- | /* none */
- {
- $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
- /*% ripper: rb_ary_new_from_args(3, Qnil, Qnil, Qnil); %*/
- }
- ;
-
excessed_comma : ','
{
/* magic number for rest_id in iseq_set_arguments() */
@@ -5069,80 +5133,80 @@ excessed_comma : ','
}
;
-block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail
+block_param : f_arg ',' f_optarg(primary_value) ',' f_rest_arg opt_args_tail(block_args_tail)
{
- $$ = new_args(p, $1, $3, $5, Qnone, $6, &@$);
+ $$ = new_args(p, $1, $3, $5, 0, $6, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), get_value($:3), get_value($:5), Qnil, get_value($:6)) %*/
}
- | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
+ | 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: ripper_new_args(p, get_value($:1), get_value($:3), get_value($:5), get_value($:7), get_value($:8)) %*/
}
- | f_arg ',' f_block_optarg opt_block_args_tail
+ | f_arg ',' f_optarg(primary_value) opt_args_tail(block_args_tail)
{
- $$ = new_args(p, $1, $3, Qnone, Qnone, $4, &@$);
+ $$ = new_args(p, $1, $3, 0, 0, $4, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), get_value($:3), Qnil, Qnil, get_value($:4)) %*/
}
- | f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail
+ | f_arg ',' f_optarg(primary_value) ',' f_arg opt_args_tail(block_args_tail)
{
- $$ = new_args(p, $1, $3, Qnone, $5, $6, &@$);
+ $$ = new_args(p, $1, $3, 0, $5, $6, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), get_value($:3), Qnil, get_value($:5), get_value($:6)) %*/
}
- | f_arg ',' f_rest_arg opt_block_args_tail
+ | f_arg ',' f_rest_arg opt_args_tail(block_args_tail)
{
- $$ = new_args(p, $1, Qnone, $3, Qnone, $4, &@$);
+ $$ = new_args(p, $1, 0, $3, 0, $4, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), Qnil, get_value($:3), Qnil, get_value($:4)) %*/
}
| f_arg excessed_comma
{
- $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@2);
- $$ = new_args(p, $1, Qnone, $2, Qnone, $$, &@$);
+ $$ = new_args_tail(p, 0, 0, 0, &@2);
+ $$ = new_args(p, $1, 0, $2, 0, $$, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), Qnil, get_value($:2), Qnil, rb_ary_new_from_args(3, Qnil, Qnil, Qnil)) %*/
}
- | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail
+ | f_arg ',' f_rest_arg ',' f_arg opt_args_tail(block_args_tail)
{
- $$ = new_args(p, $1, Qnone, $3, $5, $6, &@$);
+ $$ = new_args(p, $1, 0, $3, $5, $6, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), Qnil, get_value($:3), get_value($:5), get_value($:6)) %*/
}
- | f_arg opt_block_args_tail
+ | f_arg opt_args_tail(block_args_tail)
{
- $$ = new_args(p, $1, Qnone, Qnone, Qnone, $2, &@$);
+ $$ = new_args(p, $1, 0, 0, 0, $2, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), Qnil, Qnil, Qnil, get_value($:2)) %*/
}
- | f_block_optarg ',' f_rest_arg opt_block_args_tail
+ | f_optarg(primary_value) ',' f_rest_arg opt_args_tail(block_args_tail)
{
- $$ = new_args(p, Qnone, $1, $3, Qnone, $4, &@$);
+ $$ = new_args(p, 0, $1, $3, 0, $4, &@$);
/*% ripper: ripper_new_args(p, Qnil, get_value($:1), get_value($:3), Qnil, get_value($:4)) %*/
}
- | f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
+ | f_optarg(primary_value) ',' f_rest_arg ',' f_arg opt_args_tail(block_args_tail)
{
- $$ = new_args(p, Qnone, $1, $3, $5, $6, &@$);
+ $$ = new_args(p, 0, $1, $3, $5, $6, &@$);
/*% ripper: ripper_new_args(p, Qnil, get_value($:1), get_value($:3), get_value($:5), get_value($:6)) %*/
}
- | f_block_optarg opt_block_args_tail
+ | f_optarg(primary_value) opt_args_tail(block_args_tail)
{
- $$ = new_args(p, Qnone, $1, Qnone, Qnone, $2, &@$);
+ $$ = new_args(p, 0, $1, 0, 0, $2, &@$);
/*% ripper: ripper_new_args(p, Qnil, get_value($:1), Qnil, Qnil, get_value($:2)) %*/
}
- | f_block_optarg ',' f_arg opt_block_args_tail
+ | f_optarg(primary_value) ',' f_arg opt_args_tail(block_args_tail)
{
- $$ = new_args(p, Qnone, $1, Qnone, $3, $4, &@$);
+ $$ = new_args(p, 0, $1, 0, $3, $4, &@$);
/*% ripper: ripper_new_args(p, Qnil, get_value($:1), Qnil, get_value($:3), get_value($:4)) %*/
}
- | f_rest_arg opt_block_args_tail
+ | f_rest_arg opt_args_tail(block_args_tail)
{
- $$ = new_args(p, Qnone, Qnone, $1, Qnone, $2, &@$);
+ $$ = new_args(p, 0, 0, $1, 0, $2, &@$);
/*% ripper: ripper_new_args(p, Qnil, Qnil, get_value($:1), Qnil, get_value($:2)) %*/
}
- | f_rest_arg ',' f_arg opt_block_args_tail
+ | f_rest_arg ',' f_arg opt_args_tail(block_args_tail)
{
- $$ = new_args(p, Qnone, Qnone, $1, $3, $4, &@$);
+ $$ = new_args(p, 0, 0, $1, $3, $4, &@$);
/*% ripper: ripper_new_args(p, Qnil, Qnil, get_value($:1), get_value($:3), get_value($:4)) %*/
}
| block_args_tail
{
- $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $1, &@$);
+ $$ = new_args(p, 0, 0, 0, 0, $1, &@$);
/*% ripper: ripper_new_args(p, Qnil, Qnil, Qnil, Qnil, get_value($:1)) %*/
}
;
@@ -5350,7 +5414,7 @@ method_call : fcall paren_args
}
| primary_value tCOLON2 operation3
{
- $$ = new_qcall(p, idCOLON2, $1, $3, Qnull, &@3, &@$);
+ $$ = new_qcall(p, idCOLON2, $1, $3, 0, &@3, &@$);
/*% ripper: call!($:1, $:2, $:3) %*/
}
| primary_value call_op paren_args
@@ -5522,29 +5586,29 @@ p_top_expr : p_top_expr_body
p_top_expr_body : p_expr
| p_expr ','
{
- $$ = new_array_pattern_tail(p, Qnone, 1, Qnone, Qnone, &@$);
- $$ = new_array_pattern(p, Qnone, $1, $$, &@$);
+ $$ = new_array_pattern_tail(p, 0, 1, 0, 0, &@$);
+ $$ = new_array_pattern(p, 0, $1, $$, &@$);
/*% ripper: ripper_new_array_pattern(p, Qnil, get_value($:1), rb_ary_new()); %*/
}
| p_expr ',' p_args
{
- $$ = new_array_pattern(p, Qnone, $1, $3, &@$);
+ $$ = new_array_pattern(p, 0, $1, $3, &@$);
nd_set_first_loc($$, @1.beg_pos);
/*% ripper: ripper_new_array_pattern(p, Qnil, get_value($:1), get_value($:3)); %*/
}
| p_find
{
- $$ = new_find_pattern(p, Qnone, $1, &@$);
+ $$ = new_find_pattern(p, 0, $1, &@$);
/*% ripper: ripper_new_find_pattern(p, Qnil, get_value($:1)); %*/
}
| p_args_tail
{
- $$ = new_array_pattern(p, Qnone, Qnone, $1, &@$);
+ $$ = new_array_pattern(p, 0, 0, $1, &@$);
/*% ripper: ripper_new_array_pattern(p, Qnil, Qnil, get_value($:1)); %*/
}
| p_kwargs
{
- $$ = new_hash_pattern(p, Qnone, $1, &@$);
+ $$ = new_hash_pattern(p, 0, $1, &@$);
/*% ripper: ripper_new_hash_pattern(p, Qnil, get_value($:1)); %*/
}
;
@@ -5589,7 +5653,7 @@ p_expr_basic : p_value
| p_const p_lparen[p_pktbl] p_args rparen
{
pop_pktbl(p, $p_pktbl);
- $$ = new_array_pattern(p, $p_const, Qnone, $p_args, &@$);
+ $$ = new_array_pattern(p, $p_const, 0, $p_args, &@$);
nd_set_first_loc($$, @p_const.beg_pos);
/*% ripper: ripper_new_array_pattern(p, get_value($:p_const), Qnil, get_value($:p_args)); %*/
}
@@ -5609,14 +5673,14 @@ p_expr_basic : p_value
}
| p_const '(' rparen
{
- $$ = new_array_pattern_tail(p, Qnone, 0, Qnone, Qnone, &@$);
- $$ = new_array_pattern(p, $p_const, Qnone, $$, &@$);
+ $$ = new_array_pattern_tail(p, 0, 0, 0, 0, &@$);
+ $$ = new_array_pattern(p, $p_const, 0, $$, &@$);
/*% ripper: ripper_new_array_pattern(p, get_value($:p_const), Qnil, rb_ary_new()); %*/
}
| p_const p_lbracket[p_pktbl] p_args rbracket
{
pop_pktbl(p, $p_pktbl);
- $$ = new_array_pattern(p, $p_const, Qnone, $p_args, &@$);
+ $$ = new_array_pattern(p, $p_const, 0, $p_args, &@$);
nd_set_first_loc($$, @p_const.beg_pos);
/*% ripper: ripper_new_array_pattern(p, get_value($:p_const), Qnil, get_value($:p_args)); %*/
}
@@ -5636,24 +5700,24 @@ p_expr_basic : p_value
}
| p_const '[' rbracket
{
- $$ = new_array_pattern_tail(p, Qnone, 0, Qnone, Qnone, &@$);
- $$ = new_array_pattern(p, $1, Qnone, $$, &@$);
+ $$ = new_array_pattern_tail(p, 0, 0, 0, 0, &@$);
+ $$ = new_array_pattern(p, $1, 0, $$, &@$);
/*% ripper: ripper_new_array_pattern(p, get_value($:1), Qnil, rb_ary_new()); %*/
}
| tLBRACK p_args rbracket
{
- $$ = new_array_pattern(p, Qnone, Qnone, $p_args, &@$);
+ $$ = new_array_pattern(p, 0, 0, $p_args, &@$);
/*% ripper: ripper_new_array_pattern(p, Qnil, Qnil, get_value($:p_args)); %*/
}
| tLBRACK p_find rbracket
{
- $$ = new_find_pattern(p, Qnone, $p_find, &@$);
+ $$ = new_find_pattern(p, 0, $p_find, &@$);
/*% ripper: ripper_new_find_pattern(p, Qnil, get_value($:p_find)); %*/
}
| tLBRACK rbracket
{
- $$ = new_array_pattern_tail(p, Qnone, 0, Qnone, Qnone, &@$);
- $$ = new_array_pattern(p, Qnone, Qnone, $$, &@$);
+ $$ = new_array_pattern_tail(p, 0, 0, 0, 0, &@$);
+ $$ = new_array_pattern(p, 0, 0, $$, &@$);
/*% ripper: ripper_new_array_pattern(p, Qnil, Qnil, rb_ary_new()); %*/
}
| tLBRACE p_pktbl lex_ctxt[ctxt]
@@ -5664,13 +5728,13 @@ p_expr_basic : p_value
{
pop_pktbl(p, $p_pktbl);
p->ctxt.in_kwarg = $ctxt.in_kwarg;
- $$ = new_hash_pattern(p, Qnone, $p_kwargs, &@$);
+ $$ = new_hash_pattern(p, 0, $p_kwargs, &@$);
/*% ripper: ripper_new_hash_pattern(p, Qnil, get_value($:p_kwargs)); %*/
}
| tLBRACE rbrace
{
- $$ = new_hash_pattern_tail(p, Qnone, 0, &@$);
- $$ = new_hash_pattern(p, Qnone, $$, &@$);
+ $$ = new_hash_pattern_tail(p, 0, 0, &@$);
+ $$ = new_hash_pattern(p, 0, $$, &@$);
/*%%%*/
/*%
VALUE val = ripper_new_hash_pattern_tail(p, Qnil, 0);
@@ -5689,7 +5753,7 @@ p_expr_basic : p_value
p_args : p_expr
{
NODE *pre_args = NEW_LIST($1, &@$);
- $$ = new_array_pattern_tail(p, pre_args, 0, Qnone, Qnone, &@$);
+ $$ = new_array_pattern_tail(p, pre_args, 0, 0, 0, &@$);
/*%%%*/
/*%
VALUE ary = rb_ary_new_from_args(1, get_value($:1));
@@ -5698,7 +5762,7 @@ p_args : p_expr
}
| p_args_head
{
- $$ = new_array_pattern_tail(p, $1, 1, Qnone, Qnone, &@$);
+ $$ = new_array_pattern_tail(p, $1, 1, 0, 0, &@$);
/*%%%*/
/*%
set_value(rb_ary_new_from_args(3, get_value($:1), Qnil, Qnil));
@@ -5706,7 +5770,7 @@ p_args : p_expr
}
| p_args_head p_arg
{
- $$ = new_array_pattern_tail(p, list_concat($1, $2), 0, Qnone, Qnone, &@$);
+ $$ = new_array_pattern_tail(p, list_concat($1, $2), 0, 0, 0, &@$);
/*%%%*/
/*%
VALUE pre_args = rb_ary_concat(get_value($:1), get_value($:2));
@@ -5715,7 +5779,7 @@ p_args : p_expr
}
| p_args_head p_rest
{
- $$ = new_array_pattern_tail(p, $1, 1, $2, Qnone, &@$);
+ $$ = new_array_pattern_tail(p, $1, 1, $2, 0, &@$);
/*%%%*/
/*%
set_value(rb_ary_new_from_args(3, get_value($:1), get_value($:2), Qnil));
@@ -5745,12 +5809,12 @@ p_args_head : p_arg ','
p_args_tail : p_rest
{
- $$ = new_array_pattern_tail(p, Qnone, 1, $1, Qnone, &@$);
+ $$ = new_array_pattern_tail(p, 0, 1, $1, 0, &@$);
/*% ripper: ripper_new_array_pattern_tail(p, Qnil, get_value($:1), Qnil); %*/
}
| p_rest ',' p_args_post
{
- $$ = new_array_pattern_tail(p, Qnone, 1, $1, $3, &@$);
+ $$ = new_array_pattern_tail(p, 0, 1, $1, $3, &@$);
/*% ripper: ripper_new_array_pattern_tail(p, Qnil, get_value($:1), get_value($:3)); %*/
}
;
@@ -5808,7 +5872,7 @@ p_kwargs : p_kwarg ',' p_any_kwrest
}
| p_any_kwrest
{
- $$ = new_hash_pattern_tail(p, new_hash(p, Qnone, &@$), $1, &@$);
+ $$ = new_hash_pattern_tail(p, new_hash(p, 0, &@$), $1, &@$);
/*% ripper: ripper_new_hash_pattern_tail(p, rb_ary_new(), get_value($:1)) %*/
}
;
@@ -6112,15 +6176,7 @@ regexp : tREGEXP_BEG regexp_contents tREGEXP_END
}
;
-words_sep : ' ' {}
- | words_sep ' '
- ;
-
-words : tWORDS_BEG words_sep word_list tSTRING_END
- {
- $$ = make_list($3, &@$);
- /*% ripper: array!($:3) %*/
- }
+words : words(tWORDS_BEG, word_list) <node>
;
word_list : /* none */
@@ -6128,7 +6184,7 @@ word_list : /* none */
$$ = 0;
/*% ripper: words_new! %*/
}
- | word_list word words_sep
+ | word_list word ' '+
{
$$ = list_append(p, $1, evstr2dstr(p, $2));
/*% ripper: words_add!($:1, $:2) %*/
@@ -6144,11 +6200,7 @@ word : string_content
}
;
-symbols : tSYMBOLS_BEG words_sep symbol_list tSTRING_END
- {
- $$ = make_list($3, &@$);
- /*% ripper: array!($:3) %*/
- }
+symbols : words(tSYMBOLS_BEG, symbol_list) <node>
;
symbol_list : /* none */
@@ -6156,25 +6208,17 @@ symbol_list : /* none */
$$ = 0;
/*% ripper: symbols_new! %*/
}
- | symbol_list word words_sep
+ | symbol_list word ' '+
{
$$ = symbol_append(p, $1, evstr2dstr(p, $2));
/*% ripper: symbols_add!($:1, $:2) %*/
}
;
-qwords : tQWORDS_BEG words_sep qword_list tSTRING_END
- {
- $$ = make_list($3, &@$);
- /*% ripper: array!($:3) %*/
- }
+qwords : words(tQWORDS_BEG, qword_list) <node>
;
-qsymbols : tQSYMBOLS_BEG words_sep qsym_list tSTRING_END
- {
- $$ = make_list($3, &@$);
- /*% ripper: array!($:3) %*/
- }
+qsymbols : words(tQSYMBOLS_BEG, qsym_list) <node>
;
qword_list : /* none */
@@ -6182,7 +6226,7 @@ qword_list : /* none */
$$ = 0;
/*% ripper: qwords_new! %*/
}
- | qword_list tSTRING_CONTENT words_sep
+ | qword_list tSTRING_CONTENT ' '+
{
$$ = list_append(p, $1, $2);
/*% ripper: qwords_add!($:1, $:2) %*/
@@ -6194,7 +6238,7 @@ qsym_list : /* none */
$$ = 0;
/*% ripper: qsymbols_new! %*/
}
- | qsym_list tSTRING_CONTENT words_sep
+ | qsym_list tSTRING_CONTENT ' '+
{
$$ = symbol_append(p, $1, $2);
/*% ripper: qsymbols_add!($:1, $:2) %*/
@@ -6444,8 +6488,8 @@ f_opt_paren_args: f_paren_args
| none
{
p->ctxt.in_argdef = 0;
- $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
- $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $$, &@0);
+ $$ = new_args_tail(p, 0, 0, 0, &@0);
+ $$ = new_args(p, 0, 0, 0, 0, $$, &@0);
/*% ripper: ripper_new_args(p, Qnil, Qnil, Qnil, Qnil, rb_ary_new_from_args(3, Qnil, Qnil, Qnil)) %*/
}
;
@@ -6478,121 +6522,109 @@ f_arglist : f_paren_args
}
;
-args_tail : f_kwarg ',' f_kwrest opt_f_block_arg
+args_tail : f_kwarg(f_kw) ',' f_kwrest opt_f_block_arg
{
$$ = new_args_tail(p, $1, $3, $4, &@3);
/*% ripper: rb_ary_new_from_args(3, get_value($:1), get_value($:3), get_value($:4)); %*/
}
- | f_kwarg opt_f_block_arg
+ | f_kwarg(f_kw) opt_f_block_arg
{
- $$ = new_args_tail(p, $1, Qnone, $2, &@1);
+ $$ = new_args_tail(p, $1, 0, $2, &@1);
/*% ripper: rb_ary_new_from_args(3, get_value($:1), Qnil, get_value($:2)); %*/
}
| f_any_kwrest opt_f_block_arg
{
- $$ = new_args_tail(p, Qnone, $1, $2, &@1);
+ $$ = new_args_tail(p, 0, $1, $2, &@1);
/*% ripper: rb_ary_new_from_args(3, Qnil, get_value($:1), get_value($:2)); %*/
}
| f_block_arg
{
- $$ = new_args_tail(p, Qnone, Qnone, $1, &@1);
+ $$ = new_args_tail(p, 0, 0, $1, &@1);
/*% ripper: rb_ary_new_from_args(3, Qnil, Qnil, get_value($:1)); %*/
}
| args_forward
{
add_forwarding_args(p);
- $$ = new_args_tail(p, Qnone, $1, arg_FWD_BLOCK, &@1);
+ $$ = new_args_tail(p, 0, $1, arg_FWD_BLOCK, &@1);
$$->nd_ainfo.forwarding = 1;
/*% ripper: rb_ary_new_from_args(3, Qnil, get_value($:1), Qnil); %*/
}
;
-opt_args_tail : ',' args_tail
+f_args : f_arg ',' f_optarg(arg_value) ',' f_rest_arg opt_args_tail(args_tail)
{
- $$ = $2;
- /*% ripper: get_value($:2); %*/
- }
- | /* none */
- {
- $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
- /*% ripper: rb_ary_new_from_args(3, Qnil, Qnil, Qnil); %*/
- }
- ;
-
-f_args : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail
- {
- $$ = new_args(p, $1, $3, $5, Qnone, $6, &@$);
+ $$ = new_args(p, $1, $3, $5, 0, $6, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), get_value($:3), get_value($:5), Qnil, get_value($:6)) %*/
}
- | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
+ | f_arg ',' f_optarg(arg_value) ',' f_rest_arg ',' f_arg opt_args_tail(args_tail)
{
$$ = new_args(p, $1, $3, $5, $7, $8, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), get_value($:3), get_value($:5), get_value($:7), get_value($:8)) %*/
}
- | f_arg ',' f_optarg opt_args_tail
+ | f_arg ',' f_optarg(arg_value) opt_args_tail(args_tail)
{
- $$ = new_args(p, $1, $3, Qnone, Qnone, $4, &@$);
+ $$ = new_args(p, $1, $3, 0, 0, $4, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), get_value($:3), Qnil, Qnil, get_value($:4)) %*/
}
- | f_arg ',' f_optarg ',' f_arg opt_args_tail
+ | f_arg ',' f_optarg(arg_value) ',' f_arg opt_args_tail(args_tail)
{
- $$ = new_args(p, $1, $3, Qnone, $5, $6, &@$);
+ $$ = new_args(p, $1, $3, 0, $5, $6, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), get_value($:3), Qnil, get_value($:5), get_value($:6)) %*/
}
- | f_arg ',' f_rest_arg opt_args_tail
+ | f_arg ',' f_rest_arg opt_args_tail(args_tail)
{
- $$ = new_args(p, $1, Qnone, $3, Qnone, $4, &@$);
+ $$ = new_args(p, $1, 0, $3, 0, $4, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), Qnil, get_value($:3), Qnil, get_value($:4)) %*/
}
- | f_arg ',' f_rest_arg ',' f_arg opt_args_tail
+ | f_arg ',' f_rest_arg ',' f_arg opt_args_tail(args_tail)
{
- $$ = new_args(p, $1, Qnone, $3, $5, $6, &@$);
+ $$ = new_args(p, $1, 0, $3, $5, $6, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), Qnil, get_value($:3), get_value($:5), get_value($:6)) %*/
}
- | f_arg opt_args_tail
+ | f_arg opt_args_tail(args_tail)
{
- $$ = new_args(p, $1, Qnone, Qnone, Qnone, $2, &@$);
+ $$ = new_args(p, $1, 0, 0, 0, $2, &@$);
/*% ripper: ripper_new_args(p, get_value($:1), Qnil, Qnil, Qnil, get_value($:2)) %*/
}
- | f_optarg ',' f_rest_arg opt_args_tail
+ | f_optarg(arg_value) ',' f_rest_arg opt_args_tail(args_tail)
{
- $$ = new_args(p, Qnone, $1, $3, Qnone, $4, &@$);
+ $$ = new_args(p, 0, $1, $3, 0, $4, &@$);
/*% ripper: ripper_new_args(p, Qnil, get_value($:1), get_value($:3), Qnil, get_value($:4)) %*/
}
- | f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
+ | f_optarg(arg_value) ',' f_rest_arg ',' f_arg opt_args_tail(args_tail)
{
- $$ = new_args(p, Qnone, $1, $3, $5, $6, &@$);
+ $$ = new_args(p, 0, $1, $3, $5, $6, &@$);
/*% ripper: ripper_new_args(p, Qnil, get_value($:1), get_value($:3), get_value($:5), get_value($:6)) %*/
}
- | f_optarg opt_args_tail
+ | f_optarg(arg_value) opt_args_tail(args_tail)
{
- $$ = new_args(p, Qnone, $1, Qnone, Qnone, $2, &@$);
+ $$ = new_args(p, 0, $1, 0, 0, $2, &@$);
/*% ripper: ripper_new_args(p, Qnil, get_value($:1), Qnil, Qnil, get_value($:2)) %*/
}
- | f_optarg ',' f_arg opt_args_tail
+ | f_optarg(arg_value) ',' f_arg opt_args_tail(args_tail)
{
- $$ = new_args(p, Qnone, $1, Qnone, $3, $4, &@$);
+ $$ = new_args(p, 0, $1, 0, $3, $4, &@$);
/*% ripper: ripper_new_args(p, Qnil, get_value($:1), Qnil, get_value($:3), get_value($:4)) %*/
}
- | f_rest_arg opt_args_tail
+ | f_rest_arg opt_args_tail(args_tail)
{
- $$ = new_args(p, Qnone, Qnone, $1, Qnone, $2, &@$);
+ $$ = new_args(p, 0, 0, $1, 0, $2, &@$);
/*% ripper: ripper_new_args(p, Qnil, Qnil, get_value($:1), Qnil, get_value($:2)) %*/
}
- | f_rest_arg ',' f_arg opt_args_tail
+ | f_rest_arg ',' f_arg opt_args_tail(args_tail)
{
- $$ = new_args(p, Qnone, Qnone, $1, $3, $4, &@$);
+ $$ = new_args(p, 0, 0, $1, $3, $4, &@$);
/*% ripper: ripper_new_args(p, Qnil, Qnil, get_value($:1), get_value($:3), get_value($:4)) %*/
}
| args_tail
{
- $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $1, &@$);
+ $$ = new_args(p, 0, 0, 0, 0, $1, &@$);
/*% ripper: ripper_new_args(p, Qnil, Qnil, Qnil, Qnil, get_value($:1)) %*/
}
| /* none */
{
- $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
- $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $$, &@0);
+ $$ = new_args_tail(p, 0, 0, 0, &@0);
+ $$ = new_args(p, 0, 0, 0, 0, $$, &@0);
/*% ripper: ripper_new_args(p, Qnil, Qnil, Qnil, Qnil, rb_ary_new_from_args(3, Qnil, Qnil, Qnil)) %*/
}
;
@@ -6750,31 +6782,6 @@ f_block_kw : f_label primary_value
}
;
-f_block_kwarg : f_block_kw
- {
- $$ = $1;
- /*% ripper: rb_ary_new3(1, get_value($:1)) %*/
- }
- | f_block_kwarg ',' f_block_kw
- {
- $$ = kwd_append($1, $3);
- /*% ripper: rb_ary_push(get_value($:1), get_value($:3)) %*/
- }
- ;
-
-
-f_kwarg : f_kw
- {
- $$ = $1;
- /*% ripper: rb_ary_new3(1, get_value($:1)) %*/
- }
- | f_kwarg ',' f_kw
- {
- $$ = kwd_append($1, $3);
- /*% ripper: rb_ary_push(get_value($:1), get_value($:3)) %*/
- }
- ;
-
kwrest_mark : tPOW
| tDSTAR
;
@@ -6799,48 +6806,6 @@ f_kwrest : kwrest_mark tIDENTIFIER
}
;
-f_opt : f_arg_asgn f_eq arg_value
- {
- p->cur_arg = 0;
- p->ctxt.in_argdef = 1;
- $$ = NEW_OPT_ARG(assignable(p, $1, $3, &@$), &@$);
- /*% ripper: rb_assoc_new(ripper_assignable(p, $1, get_value($:1)), get_value($:3)) %*/
- }
- ;
-
-f_block_opt : f_arg_asgn f_eq primary_value
- {
- p->cur_arg = 0;
- p->ctxt.in_argdef = 1;
- $$ = NEW_OPT_ARG(assignable(p, $1, $3, &@$), &@$);
- /*% ripper: rb_assoc_new(ripper_assignable(p, $1, get_value($:1)), get_value($:3)) %*/
- }
- ;
-
-f_block_optarg : f_block_opt
- {
- $$ = $1;
- /*% ripper: rb_ary_new3(1, get_value($:1)) %*/
- }
- | f_block_optarg ',' f_block_opt
- {
- $$ = opt_arg_append($1, $3);
- /*% ripper: rb_ary_push(get_value($:1), get_value($:3)) %*/
- }
- ;
-
-f_optarg : f_opt
- {
- $$ = $1;
- /*% ripper: rb_ary_new3(1, get_value($:1)) %*/
- }
- | f_optarg ',' f_opt
- {
- $$ = opt_arg_append($1, $3);
- /*% ripper: rb_ary_push(get_value($:1), get_value($:3)) %*/
- }
- ;
-
restarg_mark : '*'
| tSTAR
;
@@ -6884,7 +6849,7 @@ opt_f_block_arg : ',' f_block_arg
}
| none
{
- $$ = Qnull;
+ $$ = 0;
/*% ripper: Qnil; %*/
}
;
@@ -7051,7 +7016,7 @@ terms : term
none : /* none */
{
- $$ = Qnull;
+ $$ = 0;
/*%%%*/
/*%
set_value(rb_ripper_none);
@@ -7713,7 +7678,7 @@ yycompile0(VALUE arg)
struct parser_params *p = (struct parser_params *)arg;
int cov = FALSE;
- if (!compile_for_eval && !NIL_P(p->ruby_sourcefile_string) && !e_option_supplied(p)) {
+ if (!compile_for_eval && p->ruby_sourcefile_string && !e_option_supplied(p)) {
cov = TRUE;
}
@@ -7730,7 +7695,6 @@ yycompile0(VALUE arg)
n = yyparse(p);
RUBY_DTRACE_PARSE_HOOK(END);
- rb_parser_aset_script_lines_for(p->ruby_sourcefile_string, p->debug_lines);
p->debug_lines = 0;
xfree(p->lex.strterm);
@@ -7764,21 +7728,43 @@ yycompile0(VALUE arg)
}
}
p->ast->body.root = tree;
- if (!p->ast->body.script_lines) p->ast->body.script_lines = (rb_parser_ary_t *)INT2FIX(p->line_count);
+ p->ast->body.line_count = p->line_count;
return TRUE;
}
+static void
+set_arg_error(struct parser_params *p, const char *err)
+{
+ VALUE excargs[3];
+
+ excargs[0] = rb_eArgError;
+ excargs[1] = rb_str_new_cstr(err);
+ excargs[2] = rb_make_backtrace();
+ rb_set_errinfo(rb_make_exception(3, excargs));
+}
+
static rb_ast_t *
-yycompile(struct parser_params *p, VALUE fname, int line)
+yycompile(struct parser_params *p, const char *fname_ptr, long fname_len, rb_encoding *fname_enc, int line)
{
rb_ast_t *ast;
- if (NIL_P(fname)) {
- p->ruby_sourcefile_string = Qnil;
+ if (!fname_ptr) {
+ p->ruby_sourcefile_string = NULL;
p->ruby_sourcefile = "(none)";
}
else {
- p->ruby_sourcefile_string = rb_str_to_interned_str(fname);
- p->ruby_sourcefile = StringValueCStr(fname);
+ int w;
+ if (cstr_null_check(p, fname_ptr, fname_len, fname_enc, &w)) {
+ if (w) {
+ set_arg_error(p, "string contains null char");
+ }
+ else {
+ set_arg_error(p, "string contains null byte");
+ }
+ return rb_ast_new();
+ }
+
+ p->ruby_sourcefile_string = rb_parser_encoding_string_new(p, fname_ptr, fname_len, fname_enc);
+ p->ruby_sourcefile = fname_ptr;
}
p->ruby_sourceline = line - 1;
@@ -7797,104 +7783,36 @@ yycompile(struct parser_params *p, VALUE fname, int line)
#endif /* !RIPPER */
static rb_encoding *
-must_be_ascii_compatible(struct parser_params *p, VALUE s)
+must_be_ascii_compatible(struct parser_params *p, rb_parser_string_t *s)
{
- rb_encoding *enc = rb_enc_get(s);
+ rb_encoding *enc = rb_parser_str_get_encoding(s);
if (!rb_enc_asciicompat(enc)) {
rb_raise(rb_eArgError, "invalid source encoding");
}
return enc;
}
-static VALUE
-lex_get_str(struct parser_params *p, VALUE s)
-{
- char *beg, *end, *start;
- long len;
-
- beg = RSTRING_PTR(s);
- len = RSTRING_LEN(s);
- start = beg;
- if (p->lex.gets_.ptr) {
- if (len == p->lex.gets_.ptr) return Qnil;
- beg += p->lex.gets_.ptr;
- len -= p->lex.gets_.ptr;
- }
- end = memchr(beg, '\n', len);
- if (end) len = ++end - beg;
- p->lex.gets_.ptr += len;
- return rb_str_subseq(s, beg - start, len);
-}
-
static rb_parser_string_t *
lex_getline(struct parser_params *p)
{
- rb_parser_string_t *str;
- VALUE line = (*p->lex.gets)(p, p->lex.input);
- if (NIL_P(line)) return 0;
- must_be_ascii_compatible(p, line);
+ rb_parser_string_t *line = (*p->lex.gets)(p, p->lex.input, p->line_count);
+ if (!line) return 0;
p->line_count++;
- str = rb_str_to_parser_string(p, line);
- string_buffer_append(p, str);
- return str;
+ string_buffer_append(p, line);
+ must_be_ascii_compatible(p, line);
+ return line;
}
#ifndef RIPPER
-static rb_ast_t*
-parser_compile_string(rb_parser_t *p, VALUE fname, VALUE s, int line)
-{
- p->lex.gets = lex_get_str;
- p->lex.gets_.ptr = 0;
- p->lex.input = rb_str_new_frozen(s);
- p->lex.pbeg = p->lex.pcur = p->lex.pend = 0;
-
- return yycompile(p, fname, line);
-}
-
-rb_ast_t*
-rb_ruby_parser_compile_string_path(rb_parser_t *p, VALUE f, VALUE s, int line)
-{
- must_be_ascii_compatible(p, s);
- return parser_compile_string(p, f, s, line);
-}
-
-rb_ast_t*
-rb_ruby_parser_compile_string(rb_parser_t *p, const char *f, VALUE s, int line)
-{
- return rb_ruby_parser_compile_string_path(p, rb_filesystem_str_new_cstr(f), s, line);
-}
-
-static VALUE
-lex_io_gets(struct parser_params *p, VALUE io)
-{
- return rb_io_gets_internal(io);
-}
-
-rb_ast_t*
-rb_ruby_parser_compile_file_path(rb_parser_t *p, VALUE fname, VALUE file, int start)
-{
- p->lex.gets = lex_io_gets;
- p->lex.input = file;
- p->lex.pbeg = p->lex.pcur = p->lex.pend = 0;
-
- return yycompile(p, fname, start);
-}
-
-static VALUE
-lex_generic_gets(struct parser_params *p, VALUE input)
-{
- return (*p->lex.gets_.call)(input, p->line_count);
-}
-
rb_ast_t*
-rb_ruby_parser_compile_generic(rb_parser_t *p, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int start)
+rb_parser_compile(rb_parser_t *p, rb_parser_lex_gets_func *gets,
+ const char *fname_ptr, long fname_len, rb_encoding *fname_enc, rb_parser_input_data input, int line)
{
- p->lex.gets = lex_generic_gets;
- p->lex.gets_.call = lex_gets;
+ p->lex.gets = gets;
p->lex.input = input;
p->lex.pbeg = p->lex.pcur = p->lex.pend = 0;
- return yycompile(p, fname, start);
+ return yycompile(p, fname_ptr, fname_len, fname_enc, line);
}
#endif /* !RIPPER */
@@ -8660,6 +8578,10 @@ parser_update_heredoc_indent(struct parser_params *p, int c)
}
p->heredoc_line_indent = -1;
}
+ else {
+ /* Whitespace only line has no indentation */
+ p->heredoc_line_indent = 0;
+ }
}
return FALSE;
}
@@ -9689,7 +9611,7 @@ parser_set_encode(struct parser_params *p, const char *name)
error:
excargs[0] = rb_eArgError;
excargs[2] = rb_make_backtrace();
- rb_ary_unshift(excargs[2], rb_sprintf("%"PRIsVALUE":%d", p->ruby_sourcefile_string, p->ruby_sourceline));
+ rb_ary_unshift(excargs[2], rb_sprintf("%"PRIsVALUE":%d", rb_str_new_mutable_parser_string(p->ruby_sourcefile_string), p->ruby_sourceline));
VALUE exc = rb_make_exception(3, excargs);
ruby_show_error_line(p, exc, &(YYLTYPE)RUBY_INIT_YYLLOC(), p->ruby_sourceline, p->lex.lastline);
rb_exc_raise(exc);
@@ -12666,10 +12588,10 @@ rb_node_line_new(struct parser_params *p, const YYLTYPE *loc)
}
static rb_node_file_t *
-rb_node_file_new(struct parser_params *p, VALUE str, const YYLTYPE *loc)
+rb_node_file_new(struct parser_params *p, rb_parser_string_t *str, const YYLTYPE *loc)
{
rb_node_file_t *n = NODE_NEWNODE(NODE_FILE, rb_node_file_t, loc);
- n->path = rb_str_to_parser_string(p, str);
+ n->path = str;
return n;
}
@@ -12908,17 +12830,16 @@ literal_concat0(struct parser_params *p, rb_parser_string_t *head, rb_parser_str
static rb_parser_string_t *
string_literal_head(struct parser_params *p, enum node_type htype, NODE *head)
{
- if (htype != NODE_DSTR) return false;
+ if (htype != NODE_DSTR) return NULL;
if (RNODE_DSTR(head)->nd_next) {
head = RNODE_LIST(RNODE_LIST(RNODE_DSTR(head)->nd_next)->as.nd_end)->nd_head;
- if (!head || !nd_type_p(head, NODE_STR)) return false;
+ if (!head || !nd_type_p(head, NODE_STR)) return NULL;
}
rb_parser_string_t *lit = RNODE_DSTR(head)->string;
- ASSUME(lit != false);
+ ASSUME(lit);
return lit;
}
-#ifndef RIPPER
static rb_parser_string_t *
rb_parser_string_deep_copy(struct parser_params *p, const rb_parser_string_t *orig)
{
@@ -12929,7 +12850,6 @@ rb_parser_string_deep_copy(struct parser_params *p, const rb_parser_string_t *or
copy->enc = orig->enc;
return copy;
}
-#endif
/* concat two string literals */
static NODE *
@@ -13263,9 +13183,13 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
return NEW_FALSE(loc);
case keyword__FILE__:
{
- VALUE file = p->ruby_sourcefile_string;
- if (NIL_P(file))
- file = rb_str_new(0, 0);
+ rb_parser_string_t *file;
+ if (p->ruby_sourcefile_string) {
+ file = rb_parser_string_deep_copy(p, p->ruby_sourcefile_string);
+ }
+ else {
+ file = STRING_NEW0();
+ }
node = NEW_FILE(file, loc);
}
return node;
@@ -15848,7 +15772,7 @@ parser_initialize(struct parser_params *p)
{
/* note: we rely on TypedData_Make_Struct to set most fields to 0 */
p->command_start = TRUE;
- p->ruby_sourcefile_string = Qnil;
+ p->ruby_sourcefile_string = NULL;
p->lex.lpar_beg = -1; /* make lambda_beginning_p() == FALSE at first */
string_buffer_init(p);
p->node_id = 0;
@@ -15883,9 +15807,6 @@ rb_ruby_parser_mark(void *ptr)
{
struct parser_params *p = (struct parser_params*)ptr;
- rb_gc_mark(p->lex.input);
- rb_gc_mark(p->ruby_sourcefile_string);
- rb_gc_mark((VALUE)p->ast);
#ifndef RIPPER
rb_gc_mark(p->error_buffer);
#else
@@ -15916,6 +15837,10 @@ rb_ruby_parser_free(void *ptr)
ruby_sized_xfree(p->tokenbuf, p->toksiz);
}
+ if (p->ruby_sourcefile_string) {
+ rb_parser_string_free(p, p->ruby_sourcefile_string);
+ }
+
for (local = p->lvtbl; local; local = prev) {
prev = local->prev;
local_free(p, local);
@@ -15956,20 +15881,6 @@ rb_ruby_parser_memsize(const void *ptr)
return size;
}
-#ifndef UNIVERSAL_PARSER
-#ifndef RIPPER
-static const rb_data_type_t parser_data_type = {
- "parser",
- {
- rb_ruby_parser_mark,
- rb_ruby_parser_free,
- rb_ruby_parser_memsize,
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
-};
-#endif
-#endif
-
#ifndef RIPPER
#undef rb_reserved_word
@@ -15997,6 +15908,23 @@ rb_ruby_parser_new(const rb_parser_config_t *config)
parser_initialize(p);
return p;
}
+#else
+rb_parser_t *
+rb_ruby_parser_allocate(void)
+{
+ /* parser_initialize expects fields to be set to 0 */
+ rb_parser_t *p = (rb_parser_t *)ruby_xcalloc(1, sizeof(rb_parser_t));
+ return p;
+}
+
+rb_parser_t *
+rb_ruby_parser_new(void)
+{
+ /* parser_initialize expects fields to be set to 0 */
+ rb_parser_t *p = rb_ruby_parser_allocate();
+ parser_initialize(p);
+ return p;
+}
#endif
rb_parser_t *
@@ -16026,152 +15954,10 @@ rb_ruby_parser_keep_tokens(rb_parser_t *p)
p->tokens = rb_parser_ary_new_capa_for_ast_token(p, 10);
}
-#ifndef UNIVERSAL_PARSER
-rb_ast_t*
-rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE file, int start)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- RB_GC_GUARD(vparser); /* prohibit tail call optimization */
- return rb_ruby_parser_compile_file_path(p, fname, file, start);
-}
-
-rb_ast_t*
-rb_parser_compile_generic(VALUE vparser, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int start)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- RB_GC_GUARD(vparser); /* prohibit tail call optimization */
- return rb_ruby_parser_compile_generic(p, lex_gets, fname, input, start);
-}
-
-rb_ast_t*
-rb_parser_compile_string(VALUE vparser, const char *f, VALUE s, int line)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- RB_GC_GUARD(vparser); /* prohibit tail call optimization */
- return rb_ruby_parser_compile_string(p, f, s, line);
-}
-
-rb_ast_t*
-rb_parser_compile_string_path(VALUE vparser, VALUE f, VALUE s, int line)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- RB_GC_GUARD(vparser); /* prohibit tail call optimization */
- return rb_ruby_parser_compile_string_path(p, f, s, line);
-}
-
-VALUE
-rb_parser_encoding(VALUE vparser)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- return rb_ruby_parser_encoding(p);
-}
-
-VALUE
-rb_parser_end_seen_p(VALUE vparser)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- return RBOOL(rb_ruby_parser_end_seen_p(p));
-}
-
-void
-rb_parser_error_tolerant(VALUE vparser)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_error_tolerant(p);
-}
-
-void
-rb_parser_set_script_lines(VALUE vparser)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_set_script_lines(p);
-}
-
-void
-rb_parser_keep_tokens(VALUE vparser)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_keep_tokens(p);
-}
-
-VALUE
-rb_parser_new(void)
-{
- struct parser_params *p;
- VALUE parser = TypedData_Make_Struct(0, struct parser_params,
- &parser_data_type, p);
- parser_initialize(p);
- return parser;
-}
-
-VALUE
-rb_parser_set_context(VALUE vparser, const struct rb_iseq_struct *base, int main)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_set_context(p, base, main);
- return vparser;
-}
-
-void
-rb_parser_set_options(VALUE vparser, int print, int loop, int chomp, int split)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_set_options(p, print, loop, chomp, split);
-}
-
-VALUE
-rb_parser_set_yydebug(VALUE self, VALUE flag)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_set_yydebug(p, RTEST(flag));
- return flag;
-}
-
-void
-rb_set_script_lines_for(VALUE self, VALUE path)
-{
- struct parser_params *p;
- VALUE hash;
- ID script_lines;
- CONST_ID(script_lines, "SCRIPT_LINES__");
- if (!rb_const_defined_at(rb_cObject, script_lines)) return;
- hash = rb_const_get_at(rb_cObject, script_lines);
- if (RB_TYPE_P(hash, T_HASH)) {
- rb_hash_aset(hash, path, Qtrue);
- TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_set_script_lines(p);
- }
-}
-#endif /* !UNIVERSAL_PARSER */
-
-VALUE
+rb_encoding *
rb_ruby_parser_encoding(rb_parser_t *p)
{
- return rb_enc_from_encoding(p->enc);
+ return p->enc;
}
int
@@ -16232,12 +16018,12 @@ rb_ruby_parser_set_parsing_thread(rb_parser_t *p, VALUE parsing_thread)
}
void
-rb_ruby_parser_ripper_initialize(rb_parser_t *p, VALUE (*gets)(struct parser_params*,VALUE), VALUE input, VALUE sourcefile_string, const char *sourcefile, int sourceline)
+rb_ruby_parser_ripper_initialize(rb_parser_t *p, rb_parser_lex_gets_func *gets, rb_parser_input_data input, VALUE sourcefile_string, const char *sourcefile, int sourceline)
{
p->lex.gets = gets;
p->lex.input = input;
p->eofp = 0;
- p->ruby_sourcefile_string = sourcefile_string;
+ p->ruby_sourcefile_string = rb_str_to_parser_string(p, sourcefile_string);
p->ruby_sourcefile = sourcefile;
p->ruby_sourceline = sourceline;
}
@@ -16257,7 +16043,7 @@ rb_ruby_parser_enc(rb_parser_t *p)
VALUE
rb_ruby_parser_ruby_sourcefile_string(rb_parser_t *p)
{
- return p->ruby_sourcefile_string;
+ return rb_str_new_parser_string(p->ruby_sourcefile_string);
}
int
@@ -16278,7 +16064,7 @@ rb_ruby_ripper_parse0(rb_parser_t *p)
parser_prepare(p);
p->ast = rb_ast_new();
ripper_yyparse((void*)p);
- rb_ast_dispose(p->ast);
+ rb_ast_free(p->ast);
p->ast = 0;
p->eval_tree = 0;
p->eval_tree_begin = 0;
@@ -16304,12 +16090,6 @@ rb_ruby_ripper_dedent_string(rb_parser_t *p, VALUE string, int width)
return i;
}
-VALUE
-rb_ruby_ripper_lex_get_str(rb_parser_t *p, VALUE s)
-{
- return lex_get_str(p, s);
-}
-
int
rb_ruby_ripper_initialized_p(rb_parser_t *p)
{
@@ -16400,7 +16180,7 @@ parser_compile_error(struct parser_params *p, const rb_code_location_t *loc, con
va_start(ap, fmt);
p->error_buffer =
rb_syntax_error_append(p->error_buffer,
- p->ruby_sourcefile_string,
+ p->ruby_sourcefile_string ? rb_str_new_parser_string(p->ruby_sourcefile_string) : Qnil,
lineno, column,
p->enc, fmt, ap);
va_end(ap);
diff --git a/prism/config.yml b/prism/config.yml
index 8551c95b1f..0652cc4a9f 100644
--- a/prism/config.yml
+++ b/prism/config.yml
@@ -7,13 +7,16 @@ errors:
- ARGUMENT_BARE_HASH
- ARGUMENT_BLOCK_FORWARDING
- ARGUMENT_BLOCK_MULTI
+ - ARGUMENT_CONFLICT_AMPERSAND
+ - ARGUMENT_CONFLICT_STAR
+ - ARGUMENT_CONFLICT_STAR_STAR
- ARGUMENT_FORMAL_CLASS
- ARGUMENT_FORMAL_CONSTANT
- ARGUMENT_FORMAL_GLOBAL
- ARGUMENT_FORMAL_IVAR
- ARGUMENT_FORWARDING_UNBOUND
- ARGUMENT_IN
- - ARGUMENT_NO_FORWARDING_AMP
+ - ARGUMENT_NO_FORWARDING_AMPERSAND
- ARGUMENT_NO_FORWARDING_ELLIPSES
- ARGUMENT_NO_FORWARDING_STAR
- ARGUMENT_NO_FORWARDING_STAR_STAR
@@ -95,6 +98,7 @@ errors:
- EXPECT_EXPRESSION_AFTER_SPLAT_HASH
- EXPECT_EXPRESSION_AFTER_STAR
- EXPECT_IDENT_REQ_PARAMETER
+ - EXPECT_IN_DELIMITER
- EXPECT_LPAREN_REQ_PARAMETER
- EXPECT_MESSAGE
- EXPECT_RBRACKET
@@ -123,32 +127,40 @@ errors:
- HASH_ROCKET
- HASH_TERM
- HASH_VALUE
+ - HEREDOC_IDENTIFIER
- HEREDOC_TERM
- INCOMPLETE_QUESTION_MARK
- INCOMPLETE_VARIABLE_CLASS
- - INCOMPLETE_VARIABLE_CLASS_3_3_0
+ - INCOMPLETE_VARIABLE_CLASS_3_3
- INCOMPLETE_VARIABLE_INSTANCE
- - INCOMPLETE_VARIABLE_INSTANCE_3_3_0
+ - INCOMPLETE_VARIABLE_INSTANCE_3_3
- INSTANCE_VARIABLE_BARE
- INVALID_BLOCK_EXIT
- INVALID_CHARACTER
- INVALID_ENCODING_MAGIC_COMMENT
+ - INVALID_ESCAPE_CHARACTER
- INVALID_FLOAT_EXPONENT
+ - INVALID_LOCAL_VARIABLE_READ
+ - INVALID_LOCAL_VARIABLE_WRITE
- INVALID_MULTIBYTE_CHAR
- INVALID_MULTIBYTE_CHARACTER
- INVALID_MULTIBYTE_ESCAPE
- INVALID_NUMBER_BINARY
- INVALID_NUMBER_DECIMAL
+ - INVALID_NUMBER_FRACTION
- INVALID_NUMBER_HEXADECIMAL
- INVALID_NUMBER_OCTAL
- - INVALID_NUMBER_UNDERSCORE
+ - INVALID_NUMBER_UNDERSCORE_INNER
+ - INVALID_NUMBER_UNDERSCORE_TRAILING
- INVALID_PERCENT
+ - INVALID_PERCENT_EOF
- INVALID_PRINTABLE_CHARACTER
- INVALID_RETRY_AFTER_ELSE
- INVALID_RETRY_AFTER_ENSURE
- INVALID_RETRY_WITHOUT_RESCUE
+ - INVALID_SYMBOL
- INVALID_VARIABLE_GLOBAL
- - INVALID_VARIABLE_GLOBAL_3_3_0
+ - INVALID_VARIABLE_GLOBAL_3_3
- INVALID_YIELD
- IT_NOT_ALLOWED_NUMBERED
- IT_NOT_ALLOWED_ORDINARY
@@ -182,6 +194,7 @@ errors:
- PARAMETER_ASSOC_SPLAT_MULTI
- PARAMETER_BLOCK_MULTI
- PARAMETER_CIRCULAR
+ - PARAMETER_FORWARDING_AFTER_REST
- PARAMETER_METHOD_NAME
- PARAMETER_NAME_DUPLICATED
- PARAMETER_NO_DEFAULT
@@ -192,6 +205,7 @@ errors:
- PARAMETER_STAR
- PARAMETER_UNEXPECTED_FWD
- PARAMETER_WILD_LOOSE_COMMA
+ - PARAMETER_UNEXPECTED_NO_KW
- PATTERN_CAPTURE_DUPLICATE
- PATTERN_EXPRESSION_AFTER_BRACKET
- PATTERN_EXPRESSION_AFTER_COMMA
@@ -203,9 +217,12 @@ errors:
- PATTERN_EXPRESSION_AFTER_PIPE
- PATTERN_EXPRESSION_AFTER_RANGE
- PATTERN_EXPRESSION_AFTER_REST
+ - PATTERN_HASH_IMPLICIT
- PATTERN_HASH_KEY
- PATTERN_HASH_KEY_DUPLICATE
+ - PATTERN_HASH_KEY_INTERPOLATED
- PATTERN_HASH_KEY_LABEL
+ - PATTERN_HASH_KEY_LOCALS
- PATTERN_IDENT_AFTER_HROCKET
- PATTERN_LABEL_AFTER_COMMA
- PATTERN_REST
@@ -244,6 +261,9 @@ errors:
- UNARY_RECEIVER
- UNDEF_ARGUMENT
- UNEXPECTED_BLOCK_ARGUMENT
+ - UNEXPECTED_INDEX_BLOCK
+ - UNEXPECTED_INDEX_KEYWORDS
+ - UNEXPECTED_SAFE_NAVIGATION
- UNEXPECTED_TOKEN_CLOSE_CONTEXT
- UNEXPECTED_TOKEN_IGNORE
- UNTIL_TERM
@@ -263,7 +283,7 @@ warnings:
- COMPARISON_AFTER_COMPARISON
- DOT_DOT_DOT_EOL
- EQUAL_IN_CONDITIONAL
- - EQUAL_IN_CONDITIONAL_3_3_0
+ - EQUAL_IN_CONDITIONAL_3_3
- END_IN_METHOD
- DUPLICATED_HASH_KEY
- DUPLICATED_WHEN_CLAUSE
@@ -276,6 +296,7 @@ warnings:
- KEYWORD_EOL
- LITERAL_IN_CONDITION_DEFAULT
- LITERAL_IN_CONDITION_VERBOSE
+ - SHAREABLE_CONSTANT_VALUE_LINE
- SHEBANG_CARRIAGE_RETURN
- UNEXPECTED_CARRIAGE_RETURN
- UNREACHABLE_STATEMENT
@@ -614,6 +635,8 @@ tokens:
flags:
- name: ArgumentsNodeFlags
values:
+ - name: CONTAINS_KEYWORDS
+ comment: "if arguments contain keywords"
- name: CONTAINS_KEYWORD_SPLAT
comment: "if arguments contain keyword splat"
comment: Flags for arguments nodes.
@@ -703,6 +726,11 @@ flags:
- name: FORCED_US_ASCII_ENCODING
comment: "internal bytes forced the encoding to US-ASCII"
comment: Flags for regular expression and match last line nodes.
+ - name: ReturnNodeFlags
+ values:
+ - name: REDUNDANT
+ comment: "a return statement that is redundant because it is the last statement in a method"
+ comment: Flags for return nodes.
- name: ShareableConstantNodeFlags
values:
- name: LITERAL
@@ -737,10 +765,25 @@ nodes:
fields:
- name: new_name
type: node
+ comment: |
+ Represents the new name of the global variable that can be used after aliasing. This can be either a global variable, a back reference, or a numbered reference.
+
+ alias $foo $bar
+ ^^^^
- name: old_name
type: node
+ comment: |
+ Represents the old name of the global variable that could be used before aliasing. This can be either a global variable, a back reference, or a numbered reference.
+
+ alias $foo $bar
+ ^^^^
- name: keyword_loc
type: location
+ comment: |
+ The location of the `alias` keyword.
+
+ alias $foo $bar
+ ^^^^^
comment: |
Represents the use of the `alias` keyword to alias a global variable.
@@ -825,10 +868,25 @@ nodes:
kind: ArrayNodeFlags
- name: elements
type: node[]
+ comment: Represent the list of zero or more [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression) within the array.
- name: opening_loc
type: location?
+ comment: |
+ Represents the optional source location for the opening token.
+
+ [1,2,3] # "["
+ %w[foo bar baz] # "%w["
+ %I(apple orange banana) # "%I("
+ foo = 1, 2, 3 # nil
- name: closing_loc
type: location?
+ comment: |
+ Represents the optional source location for the closing token.
+
+ [1,2,3] # "]"
+ %w[foo bar baz] # "]"
+ %I(apple orange banana) # ")"
+ foo = 1, 2, 3 # nil
comment: |
Represents an array literal. This can be a regular array using brackets or a special array using % like %w or %i.
@@ -1047,8 +1105,18 @@ nodes:
- name: arguments
type: node?
kind: ArgumentsNode
+ comment: |
+ The arguments to the break statement, if present. These can be any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
+
+ break foo
+ ^^^
- name: keyword_loc
type: location
+ comment: |
+ The location of the `break` keyword.
+
+ break foo
+ ^^^^^
comment: |
Represents the use of the `break` keyword.
@@ -1146,9 +1214,9 @@ nodes:
type: constant
- name: write_name
type: constant
- - name: operator
+ - name: binary_operator
type: constant
- - name: operator_loc
+ - name: binary_operator_loc
type: location
- name: value
type: node
@@ -1304,11 +1372,11 @@ nodes:
type: constant
- name: name_loc
type: location
- - name: operator_loc
+ - name: binary_operator_loc
type: location
- name: value
type: node
- - name: operator
+ - name: binary_operator
type: constant
comment: |
Represents assigning to a class variable using an operator that isn't `=`.
@@ -1374,8 +1442,7 @@ nodes:
- name: value
type: node
comment: |
- The value to assign to the class variable. Can be any node that
- represents a non-void expression.
+ The value to write to the class variable. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
@@foo = :bar
^^^^
@@ -1415,11 +1482,11 @@ nodes:
type: constant
- name: name_loc
type: location
- - name: operator_loc
+ - name: binary_operator_loc
type: location
- name: value
type: node
- - name: operator
+ - name: binary_operator
type: constant
comment: |
Represents assigning to a constant using an operator that isn't `=`.
@@ -1459,13 +1526,40 @@ nodes:
fields:
- name: parent
type: node?
- - name: child
- type: node
- kind:
- - ConstantReadNode
- - MissingNode
+ comment: |
+ The left-hand node of the path, if present. It can be `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). It will be `nil` when the constant lookup is at the root of the module tree.
+
+ Foo::Bar
+ ^^^
+
+ self::Test
+ ^^^^
+
+ a.b::C
+ ^^^
+ - name: name
+ type: constant?
+ comment: The name of the constant being accessed. This could be `nil` in the event of a syntax error.
- name: delimiter_loc
type: location
+ comment: |
+ The location of the `::` delimiter.
+
+ ::Foo
+ ^^
+
+ One::Two
+ ^^
+ - name: name_loc
+ type: location
+ comment: |
+ The location of the name of the constant.
+
+ ::Foo
+ ^^^
+
+ One::Two
+ ^^^
comment: |
Represents accessing a constant through a path of `::` operators.
@@ -1476,11 +1570,11 @@ nodes:
- name: target
type: node
kind: ConstantPathNode
- - name: operator_loc
+ - name: binary_operator_loc
type: location
- name: value
type: node
- - name: operator
+ - name: binary_operator
type: constant
comment: |
Represents assigning to a constant path using an operator that isn't `=`.
@@ -1505,13 +1599,12 @@ nodes:
fields:
- name: parent
type: node?
- - name: child
- type: node
- kind:
- - ConstantReadNode
- - MissingNode
+ - name: name
+ type: constant?
- name: delimiter_loc
type: location
+ - name: name_loc
+ type: location
comment: |
Represents writing to a constant path in a context that doesn't have an explicit value.
@@ -1522,10 +1615,28 @@ nodes:
- name: target
type: node
kind: ConstantPathNode
+ comment: |
+ A node representing the constant path being written to.
+
+ Foo::Bar = 1
+ ^^^^^^^^
+
+ ::Foo = :abc
+ ^^^^^
- name: operator_loc
type: location
+ comment: |
+ The location of the `=` operator.
+
+ ::ABC = 123
+ ^
- name: value
type: node
+ comment: |
+ The value to write to the constant path. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
+
+ FOO::BAR = :abc
+ ^^^^
comment: |
Represents writing to a constant path.
@@ -1565,12 +1676,36 @@ nodes:
fields:
- name: name
type: constant
+ comment: |
+ The name of the [constant](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#constants).
+
+ Foo = :bar # name `:Foo`
+
+ XYZ = 1 # name `:XYZ`
- name: name_loc
type: location
+ comment: |
+ The location of the constant name.
+
+ FOO = 1
+ ^^^
- name: value
type: node
+ comment: |
+ The value to write to the constant. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
+
+ FOO = :bar
+ ^^^^
+
+ MyClass = Class.new
+ ^^^^^^^^^
- name: operator_loc
type: location
+ comment: |
+ The location of the `=` operator.
+
+ FOO = :bar
+ ^
comment: |
Represents writing to a constant.
@@ -1806,11 +1941,11 @@ nodes:
type: constant
- name: name_loc
type: location
- - name: operator_loc
+ - name: binary_operator_loc
type: location
- name: value
type: node
- - name: operator
+ - name: binary_operator
type: constant
comment: |
Represents assigning to a global variable using an operator that isn't `=`.
@@ -1860,12 +1995,36 @@ nodes:
fields:
- name: name
type: constant
+ comment: |
+ The name of the global variable, which is a `$` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifier). Alternatively, it can be one of the special global variables designated by a symbol.
+
+ $foo = :bar # name `:$foo`
+
+ $_Test = 123 # name `:$_Test`
- name: name_loc
type: location
+ comment: |
+ The location of the global variable's name.
+
+ $foo = :bar
+ ^^^^
- name: value
type: node
+ comment: |
+ The value to write to the global variable. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
+
+ $foo = :bar
+ ^^^^
+
+ $-xyz = 123
+ ^^^
- name: operator_loc
type: location
+ comment: |
+ The location of the `=` operator.
+
+ $foo = :bar
+ ^
comment: |
Represents writing to a global variable.
@@ -1933,26 +2092,87 @@ nodes:
fields:
- name: if_keyword_loc
type: location?
+ comment: |
+ The location of the `if` keyword if present.
+
+ bar if foo
+ ^^
+
+ The `if_keyword_loc` field will be `nil` when the `IfNode` represents a ternary expression.
- name: predicate
type: node
+ comment: |
+ The node for the condition the `IfNode` is testing.
+
+ if foo
+ ^^^
+ bar
+ end
+
+ bar if foo
+ ^^^
+
+ foo ? bar : baz
+ ^^^
- name: then_keyword_loc
type: location?
+ comment: |
+ The location of the `then` keyword (if present) or the `?` in a ternary expression, `nil` otherwise.
+
+ if foo then bar end
+ ^^^^
+
+ a ? b : c
+ ^
- name: statements
type: node?
kind: StatementsNode
+ comment: |
+ Represents the body of statements that will be executed when the predicate is evaluated as truthy. Will be `nil` when no body is provided.
+
+ if foo
+ bar
+ ^^^
+ baz
+ ^^^
+ end
- name: consequent
type: node?
+ comment: |
+ Represents an `ElseNode` or an `IfNode` when there is an `else` or an `elsif` in the `if` statement.
+
+ if foo
+ bar
+ elsif baz
+ ^^^^^^^^^
+ qux
+ ^^^
+ end
+ ^^^
+
+ if foo then bar else baz end
+ ^^^^^^^^^^^^
- name: end_keyword_loc
type: location?
+ comment: |
+ The location of the `end` keyword if present, `nil` otherwise.
+
+ if foo
+ bar
+ end
+ ^^^
newline: predicate
comment: |
- Represents the use of the `if` keyword, either in the block form or the modifier form.
+ Represents the use of the `if` keyword, either in the block form or the modifier form, or a ternary expression.
bar if foo
^^^^^^^^^^
if foo then bar end
^^^^^^^^^^^^^^^^^^^
+
+ foo ? bar : baz
+ ^^^^^^^^^^^^^^^
- name: ImaginaryNode
fields:
- name: numeric
@@ -2057,9 +2277,9 @@ nodes:
type: location
- name: block
type: node?
- - name: operator
+ - name: binary_operator
type: constant
- - name: operator_loc
+ - name: binary_operator_loc
type: location
- name: value
type: node
@@ -2145,11 +2365,11 @@ nodes:
type: constant
- name: name_loc
type: location
- - name: operator_loc
+ - name: binary_operator_loc
type: location
- name: value
type: node
- - name: operator
+ - name: binary_operator
type: constant
comment: |
Represents assigning to an instance variable using an operator that isn't `=`.
@@ -2215,8 +2435,7 @@ nodes:
- name: value
type: node
comment: |
- The value to assign to the instance variable. Can be any node that
- represents a non-void expression.
+ The value to write to the instance variable. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
@foo = :bar
^^^^
@@ -2426,13 +2645,13 @@ nodes:
fields:
- name: name_loc
type: location
- - name: operator_loc
+ - name: binary_operator_loc
type: location
- name: value
type: node
- name: name
type: constant
- - name: operator
+ - name: binary_operator
type: constant
- name: depth
type: uint32
@@ -2507,14 +2726,50 @@ nodes:
fields:
- name: name
type: constant
+ comment: |
+ The name of the local variable, which is an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
+
+ foo = :bar # name `:foo`
+
+ abc = 123 # name `:abc`
- name: depth
type: uint32
+ comment: |
+ The number of semantic scopes we have to traverse to find the declaration of this variable.
+
+ foo = 1 # depth 0
+
+ tap { foo = 1 } # depth 1
+
+ The specific rules for calculating the depth may differ from individual Ruby implementations, as they are not specified by the language. For more information, see [the Prism documentation](https://github.com/ruby/prism/blob/main/docs/local_variable_depth.md).
- name: name_loc
type: location
+ comment: |
+ The location of the variable name.
+
+ foo = :bar
+ ^^^
- name: value
type: node
+ comment: |
+ The value to write to the local variable. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
+
+ foo = :bar
+ ^^^^
+
+ abc = 1234
+ ^^^^
+
+ Note that since the name of a local variable is known before the value is parsed, it is valid for a local variable to appear within the value of its own write.
+
+ foo = foo
- name: operator_loc
type: location
+ comment: |
+ The location of the `=` operator.
+
+ x = :y
+ ^
comment: |
Represents writing to a local variable.
@@ -2831,6 +3086,8 @@ nodes:
# On parsing error of `f(**kwargs, ...)` or `f(**nil, ...)`, the keyword_rest value is moved here:
- KeywordRestParameterNode
- NoKeywordsParameterNode
+ # On parsing error of `f(..., ...)`, the first forwarding parameter is moved here:
+ - ForwardingParameterNode
- name: keywords
type: node[]
kind:
@@ -3095,6 +3352,9 @@ nodes:
^^^^^
- name: ReturnNode
fields:
+ - name: flags
+ type: flags
+ kind: ReturnNodeFlags
- name: keyword_loc
type: location
- name: arguments
@@ -3166,6 +3426,7 @@ nodes:
kind: StringFlags
- 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 use of the `__FILE__` keyword.
@@ -3287,18 +3548,55 @@ nodes:
fields:
- name: keyword_loc
type: location
+ comment: |
+ The location of the `unless` keyword.
+
+ unless cond then bar end
+ ^^^^^^
+
+ bar unless cond
+ ^^^^^^
- name: predicate
type: node
+ comment: |
+ The condition to be evaluated for the unless expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
+
+ unless cond then bar end
+ ^^^^
+
+ bar unless cond
+ ^^^^
- name: then_keyword_loc
type: location?
+ comment:
+ The location of the `then` keyword, if present.
+
+ unless cond then bar end
+ ^^^^
- name: statements
type: node?
kind: StatementsNode
+ comment: |
+ The body of statements that will executed if the unless condition is
+ falsey. Will be `nil` if no body is provided.
+
+ unless cond then bar end
+ ^^^
- name: consequent
type: node?
kind: ElseNode
+ comment: |
+ 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.
+
+ unless cond then bar end
+ ^^^
newline: predicate
comment: |
Represents the use of the `unless` keyword, either in the block form or the modifier form.
diff --git a/prism/extension.c b/prism/extension.c
index 807c8f69dc..84872914c4 100644
--- a/prism/extension.c
+++ b/prism/extension.c
@@ -19,7 +19,9 @@ VALUE rb_cPrismEmbDocComment;
VALUE rb_cPrismMagicComment;
VALUE rb_cPrismParseError;
VALUE rb_cPrismParseWarning;
+VALUE rb_cPrismResult;
VALUE rb_cPrismParseResult;
+VALUE rb_cPrismParseLexResult;
VALUE rb_cPrismDebugEncoding;
@@ -30,6 +32,7 @@ ID rb_option_id_frozen_string_literal;
ID rb_option_id_line;
ID rb_option_id_scopes;
ID rb_option_id_version;
+ID rb_prism_source_id_for;
/******************************************************************************/
/* IO of Ruby code */
@@ -515,7 +518,7 @@ parser_warnings(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
* Create a new parse result from the given parser, value, encoding, and source.
*/
static VALUE
-parse_result_create(pm_parser_t *parser, VALUE value, rb_encoding *encoding, VALUE source) {
+parse_result_create(VALUE class, pm_parser_t *parser, VALUE value, rb_encoding *encoding, VALUE source) {
VALUE result_argv[] = {
value,
parser_comments(parser, source),
@@ -526,7 +529,7 @@ parse_result_create(pm_parser_t *parser, VALUE value, rb_encoding *encoding, VAL
source
};
- return rb_class_new_instance(7, result_argv, rb_cPrismParseResult);
+ return rb_class_new_instance(7, result_argv, class);
}
/******************************************************************************/
@@ -597,8 +600,7 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod
VALUE source_string = rb_str_new((const char *) pm_string_source(input), pm_string_length(input));
VALUE offsets = rb_ary_new();
- VALUE source_argv[] = { source_string, LONG2NUM(parser.start_line), offsets };
- VALUE source = rb_class_new_instance(3, source_argv, rb_cPrismSource);
+ VALUE source = rb_funcall(rb_cPrismSource, rb_prism_source_id_for, 3, source_string, LONG2NUM(parser.start_line), offsets);
parse_lex_data_t parse_lex_data = {
.source = source,
@@ -635,7 +637,7 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod
value = parse_lex_data.tokens;
}
- VALUE result = parse_result_create(&parser, value, parse_lex_data.encoding, source);
+ VALUE result = parse_result_create(rb_cPrismParseLexResult, &parser, value, parse_lex_data.encoding, source);
pm_node_destroy(&parser, node);
pm_parser_free(&parser);
@@ -700,7 +702,7 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
VALUE source = pm_source_new(&parser, encoding);
VALUE value = pm_ast_new(&parser, node, encoding, source);
- VALUE result = parse_result_create(&parser, value, encoding, source) ;
+ VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source) ;
pm_node_destroy(&parser, node);
pm_parser_free(&parser);
@@ -804,7 +806,7 @@ parse_stream(int argc, VALUE *argv, VALUE self) {
VALUE source = pm_source_new(&parser, encoding);
VALUE value = pm_ast_new(&parser, node, encoding, source);
- VALUE result = parse_result_create(&parser, value, encoding, source);
+ VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source);
pm_node_destroy(&parser, node);
pm_buffer_free(&buffer);
@@ -1241,7 +1243,7 @@ static_inspect(int argc, VALUE *argv, VALUE self) {
pm_node_t *node = ((pm_program_node_t *) program)->statements->body.nodes[0];
pm_buffer_t buffer = { 0 };
- pm_static_literal_inspect(&buffer, &parser, node);
+ pm_static_literal_inspect(&buffer, &parser.newline_list, parser.start_line, parser.encoding->name, node);
rb_encoding *encoding = rb_enc_find(parser.encoding->name);
VALUE result = rb_enc_str_new(pm_buffer_value(&buffer), pm_buffer_length(&buffer), encoding);
@@ -1362,7 +1364,10 @@ Init_prism(void) {
rb_cPrismMagicComment = rb_define_class_under(rb_cPrism, "MagicComment", rb_cObject);
rb_cPrismParseError = rb_define_class_under(rb_cPrism, "ParseError", rb_cObject);
rb_cPrismParseWarning = rb_define_class_under(rb_cPrism, "ParseWarning", rb_cObject);
- rb_cPrismParseResult = rb_define_class_under(rb_cPrism, "ParseResult", rb_cObject);
+
+ rb_cPrismResult = rb_define_class_under(rb_cPrism, "Result", rb_cObject);
+ rb_cPrismParseResult = rb_define_class_under(rb_cPrism, "ParseResult", rb_cPrismResult);
+ rb_cPrismParseLexResult = rb_define_class_under(rb_cPrism, "ParseLexResult", rb_cPrismResult);
// Intern all of the options that we support so that we don't have to do it
// every time we parse.
@@ -1374,6 +1379,8 @@ Init_prism(void) {
rb_option_id_scopes = rb_intern_const("scopes");
rb_option_id_version = rb_intern_const("version");
+ rb_prism_source_id_for = rb_intern("for");
+
/**
* The version of the prism library.
*/
diff --git a/prism/extension.h b/prism/extension.h
index 59a3f0232a..b15a2c5e61 100644
--- a/prism/extension.h
+++ b/prism/extension.h
@@ -1,7 +1,7 @@
#ifndef PRISM_EXT_NODE_H
#define PRISM_EXT_NODE_H
-#define EXPECTED_PRISM_VERSION "0.25.0"
+#define EXPECTED_PRISM_VERSION "0.29.0"
#include <ruby.h>
#include <ruby/encoding.h>
diff --git a/prism/options.c b/prism/options.c
index 4d0d6dbc49..664db4f061 100644
--- a/prism/options.c
+++ b/prism/options.c
@@ -58,8 +58,8 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length
case 5:
assert(version != NULL);
- if (strncmp(version, "3.3.0", length) == 0) {
- options->version = PM_OPTIONS_VERSION_CRUBY_3_3_0;
+ if ((strncmp(version, "3.3.0", length) == 0) || (strncmp(version, "3.3.1", length) == 0)) {
+ options->version = PM_OPTIONS_VERSION_CRUBY_3_3;
return true;
}
diff --git a/prism/options.h b/prism/options.h
index d0b46a0864..a623ae0b83 100644
--- a/prism/options.h
+++ b/prism/options.h
@@ -49,8 +49,8 @@ typedef enum {
/** The current version of prism. */
PM_OPTIONS_VERSION_LATEST = 0,
- /** The vendored version of prism in CRuby 3.3.0. */
- PM_OPTIONS_VERSION_CRUBY_3_3_0 = 1
+ /** The vendored version of prism in CRuby 3.3.x. */
+ PM_OPTIONS_VERSION_CRUBY_3_3 = 1
} pm_options_version_t;
/**
diff --git a/prism/parser.h b/prism/parser.h
index b35026e6a2..8054e332f7 100644
--- a/prism/parser.h
+++ b/prism/parser.h
@@ -10,6 +10,7 @@
#include "prism/ast.h"
#include "prism/encoding.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"
@@ -718,6 +719,15 @@ struct pm_parser {
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.
*/
diff --git a/prism/prism.c b/prism/prism.c
index 18675b994a..02c2088089 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -672,6 +672,26 @@ pm_parser_warn_node(pm_parser_t *parser, const pm_node_t *node, pm_diagnostic_id
#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__)
+/**
+ * Add an error for an expected heredoc terminator. This is a special function
+ * only because it grabs its location off of a lex mode instead of a node or a
+ * token.
+ */
+static void
+pm_parser_err_heredoc_term(pm_parser_t *parser, pm_lex_mode_t *lex_mode) {
+ const uint8_t *ident_start = lex_mode->as.heredoc.ident_start;
+ size_t ident_length = lex_mode->as.heredoc.ident_length;
+
+ PM_PARSER_ERR_FORMAT(
+ parser,
+ ident_start,
+ ident_start + ident_length,
+ PM_ERR_HEREDOC_TERM,
+ (int) ident_length,
+ (const char *) ident_start
+ );
+}
+
/******************************************************************************/
/* Scope-related functions */
/******************************************************************************/
@@ -729,42 +749,97 @@ pm_parser_scope_find(pm_parser_t *parser, uint32_t depth) {
return scope;
}
-static void
-pm_parser_scope_forwarding_param_check(pm_parser_t *parser, const pm_token_t * token, const uint8_t mask, pm_diagnostic_id_t diag) {
+typedef enum {
+ PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
+ PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
+ PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
+} pm_scope_forwarding_param_check_result_t;
+
+static pm_scope_forwarding_param_check_result_t
+pm_parser_scope_forwarding_param_check(pm_parser_t *parser, const uint8_t mask) {
pm_scope_t *scope = parser->current_scope;
- while (scope) {
+ bool conflict = false;
+
+ while (scope != NULL) {
if (scope->parameters & mask) {
- if (!scope->closed) {
- pm_parser_err_token(parser, token, diag);
- return;
+ if (scope->closed) {
+ if (conflict) {
+ return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
+ } else {
+ return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
+ }
}
- return;
+
+ conflict = true;
}
+
if (scope->closed) break;
scope = scope->previous;
}
- pm_parser_err_token(parser, token, diag);
+ return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
}
-static inline void
+static void
pm_parser_scope_forwarding_block_check(pm_parser_t *parser, const pm_token_t * token) {
- pm_parser_scope_forwarding_param_check(parser, token, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK, PM_ERR_ARGUMENT_NO_FORWARDING_AMP);
+ switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
+ // Pass.
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
+ break;
+ }
}
-static inline void
+static void
pm_parser_scope_forwarding_positionals_check(pm_parser_t *parser, const pm_token_t * token) {
- pm_parser_scope_forwarding_param_check(parser, token, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
+ switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
+ // Pass.
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
+ break;
+ }
}
-static inline void
-pm_parser_scope_forwarding_all_check(pm_parser_t *parser, const pm_token_t * token) {
- pm_parser_scope_forwarding_param_check(parser, token, PM_SCOPE_PARAMETERS_FORWARDING_ALL, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
+static void
+pm_parser_scope_forwarding_all_check(pm_parser_t *parser, const pm_token_t *token) {
+ switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
+ // Pass.
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
+ // This shouldn't happen, because ... is not allowed in the
+ // declaration of blocks. If we get here, we assume we already have
+ // an error for this.
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
+ break;
+ }
}
-static inline void
+static void
pm_parser_scope_forwarding_keywords_check(pm_parser_t *parser, const pm_token_t * token) {
- pm_parser_scope_forwarding_param_check(parser, token, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
+ switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
+ // Pass.
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
+ break;
+ }
}
/**
@@ -1405,7 +1480,7 @@ pm_conditional_predicate_warn_write_literal_p(const pm_node_t *node) {
static 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_0 ? PM_WARN_EQUAL_IN_CONDITIONAL_3_3_0 : 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);
}
}
@@ -1555,7 +1630,7 @@ 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_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 })
@@ -1683,7 +1758,7 @@ char_is_identifier_utf8(const uint8_t *b, const uint8_t *end) {
* it's important that it be as fast as possible.
*/
static inline size_t
-char_is_identifier(pm_parser_t *parser, const uint8_t *b) {
+char_is_identifier(const pm_parser_t *parser, const uint8_t *b) {
if (parser->encoding_changed) {
size_t width;
if ((width = parser->encoding->alnum_char(b, parser->end - b)) != 0) {
@@ -2752,8 +2827,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.start = parser->start;
- node->base.location.end = parser->start;
+ node->base.location = PM_LOCATION_NULL_VALUE(parser);
node->arguments = arguments;
node->name = name;
@@ -2924,6 +2998,29 @@ pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
}
/**
+ * Validate that index expressions do not have keywords or blocks if we are
+ * parsing as Ruby 3.4+.
+ */
+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 (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) {
+ if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
+ pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
+ break;
+ }
+ }
+ }
+
+ if (block != NULL) {
+ pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
+ }
+ }
+}
+
+/**
* Allocate and initialize a new IndexAndWriteNode node.
*/
static pm_index_and_write_node_t *
@@ -2931,6 +3028,8 @@ pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, cons
assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
pm_index_and_write_node_t *node = PM_ALLOC_NODE(parser, pm_index_and_write_node_t);
+ pm_index_arguments_check(parser, target->arguments, target->block);
+
*node = (pm_index_and_write_node_t) {
{
.type = PM_INDEX_AND_WRITE_NODE,
@@ -2980,8 +3079,8 @@ pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target,
.message_loc = target->message_loc,
.read_name = 0,
.write_name = target->name,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
+ .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
+ .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
.value = value
};
@@ -3002,6 +3101,8 @@ static pm_index_operator_write_node_t *
pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
pm_index_operator_write_node_t *node = PM_ALLOC_NODE(parser, pm_index_operator_write_node_t);
+ pm_index_arguments_check(parser, target->arguments, target->block);
+
*node = (pm_index_operator_write_node_t) {
{
.type = PM_INDEX_OPERATOR_WRITE_NODE,
@@ -3017,8 +3118,8 @@ pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target,
.arguments = target->arguments,
.closing_loc = target->closing_loc,
.block = target->block,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
+ .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
+ .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
.value = value
};
@@ -3075,6 +3176,8 @@ pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
pm_index_or_write_node_t *node = PM_ALLOC_NODE(parser, pm_index_or_write_node_t);
+ pm_index_arguments_check(parser, target->arguments, target->block);
+
*node = (pm_index_or_write_node_t) {
{
.type = PM_INDEX_OR_WRITE_NODE,
@@ -3139,6 +3242,8 @@ pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
pm_index_target_node_t *node = PM_ALLOC_NODE(parser, pm_index_target_node_t);
pm_node_flags_t flags = target->base.flags;
+ pm_index_arguments_check(parser, target->arguments, target->block);
+
*node = (pm_index_target_node_t) {
{
.type = PM_INDEX_TARGET_NODE,
@@ -3358,9 +3463,9 @@ pm_class_variable_operator_write_node_create(pm_parser_t *parser, pm_class_varia
},
.name = target->name,
.name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
+ .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
.value = value,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
+ .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
};
return node;
@@ -3474,9 +3579,9 @@ pm_constant_path_operator_write_node_create(pm_parser_t *parser, pm_constant_pat
}
},
.target = target,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
+ .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
.value = value,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
+ .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
};
return node;
@@ -3510,22 +3615,27 @@ pm_constant_path_or_write_node_create(pm_parser_t *parser, pm_constant_path_node
* Allocate and initialize a new ConstantPathNode node.
*/
static pm_constant_path_node_t *
-pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, pm_node_t *child) {
+pm_constant_path_node_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_ALLOC_NODE(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,
.location = {
.start = parent == NULL ? delimiter->start : parent->location.start,
- .end = child->location.end
+ .end = name_token->end
},
},
.parent = parent,
- .child = child,
- .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter)
+ .name = name,
+ .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
+ .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
};
return node;
@@ -3596,9 +3706,9 @@ pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_nod
},
.name = target->name,
.name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
+ .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
.value = value,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
+ .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
};
return node;
@@ -3717,6 +3827,113 @@ pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
}
/**
+ * When a method body is created, we want to check if the last statement is a
+ * return or a statement that houses a return. If it is, then we want to mark
+ * that return as being redundant so that we can compile it differently but also
+ * so that we can indicate that to the user.
+ */
+static void
+pm_def_node_body_redundant_return(pm_node_t *node) {
+ switch (PM_NODE_TYPE(node)) {
+ case PM_RETURN_NODE:
+ node->flags |= PM_RETURN_NODE_FLAGS_REDUNDANT;
+ break;
+ case PM_BEGIN_NODE: {
+ pm_begin_node_t *cast = (pm_begin_node_t *) node;
+
+ if (cast->statements != NULL && cast->else_clause == NULL) {
+ pm_def_node_body_redundant_return((pm_node_t *) cast->statements);
+ }
+ break;
+ }
+ case PM_STATEMENTS_NODE: {
+ pm_statements_node_t *cast = (pm_statements_node_t *) node;
+
+ if (cast->body.size > 0) {
+ pm_def_node_body_redundant_return(cast->body.nodes[cast->body.size - 1]);
+ }
+ break;
+ }
+ case PM_IF_NODE: {
+ pm_if_node_t *cast = (pm_if_node_t *) node;
+
+ if (cast->statements != NULL) {
+ pm_def_node_body_redundant_return((pm_node_t *) cast->statements);
+ }
+
+ if (cast->consequent != NULL) {
+ pm_def_node_body_redundant_return(cast->consequent);
+ }
+ break;
+ }
+ case PM_UNLESS_NODE: {
+ pm_unless_node_t *cast = (pm_unless_node_t *) node;
+
+ if (cast->statements != NULL) {
+ pm_def_node_body_redundant_return((pm_node_t *) cast->statements);
+ }
+
+ if (cast->consequent != NULL) {
+ pm_def_node_body_redundant_return((pm_node_t *) cast->consequent);
+ }
+ break;
+ }
+ case PM_ELSE_NODE: {
+ pm_else_node_t *cast = (pm_else_node_t *) node;
+
+ if (cast->statements != NULL) {
+ pm_def_node_body_redundant_return((pm_node_t *) cast->statements);
+ }
+ break;
+ }
+ case PM_CASE_NODE: {
+ pm_case_node_t *cast = (pm_case_node_t *) node;
+ pm_node_t *condition;
+
+ PM_NODE_LIST_FOREACH(&cast->conditions, index, condition) {
+ pm_def_node_body_redundant_return(condition);
+ }
+
+ if (cast->consequent != NULL) {
+ pm_def_node_body_redundant_return((pm_node_t *) cast->consequent);
+ }
+ break;
+ }
+ case PM_WHEN_NODE: {
+ pm_when_node_t *cast = (pm_when_node_t *) node;
+
+ if (cast->statements != NULL) {
+ pm_def_node_body_redundant_return((pm_node_t *) cast->statements);
+ }
+ break;
+ }
+ case PM_CASE_MATCH_NODE: {
+ pm_case_match_node_t *cast = (pm_case_match_node_t *) node;
+ pm_node_t *condition;
+
+ PM_NODE_LIST_FOREACH(&cast->conditions, index, condition) {
+ pm_def_node_body_redundant_return(condition);
+ }
+
+ if (cast->consequent != NULL) {
+ pm_def_node_body_redundant_return((pm_node_t *) cast->consequent);
+ }
+ break;
+ }
+ case PM_IN_NODE: {
+ pm_in_node_t *cast = (pm_in_node_t *) node;
+
+ if (cast->statements != NULL) {
+ pm_def_node_body_redundant_return((pm_node_t *) cast->statements);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/**
* Allocate and initialize a new DefNode node.
*/
static pm_def_node_t *
@@ -3748,6 +3965,10 @@ pm_def_node_create(
pm_def_node_receiver_check(parser, receiver);
}
+ if (body != NULL) {
+ pm_def_node_body_redundant_return(body);
+ }
+
*node = (pm_def_node_t) {
{
.type = PM_DEF_NODE,
@@ -4338,9 +4559,9 @@ pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *ta
},
.name = pm_global_variable_write_name(parser, target),
.name_loc = target->location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
+ .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
.value = value,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
+ .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
};
return node;
@@ -4399,7 +4620,7 @@ pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant
*node = (pm_global_variable_read_node_t) {
{
.type = PM_GLOBAL_VARIABLE_READ_NODE,
- .location = { .start = parser->start, .end = parser->start }
+ .location = PM_LOCATION_NULL_VALUE(parser)
},
.name = name
};
@@ -4441,11 +4662,11 @@ pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constan
*node = (pm_global_variable_write_node_t) {
{
.type = PM_GLOBAL_VARIABLE_WRITE_NODE,
- .location = { .start = parser->start, .end = parser->start }
+ .location = PM_LOCATION_NULL_VALUE(parser)
},
.name = name,
- .name_loc = { .start = parser->start, .end = parser->start },
- .operator_loc = { .start = parser->start, .end = parser->start },
+ .name_loc = PM_LOCATION_NULL_VALUE(parser),
+ .operator_loc = PM_LOCATION_NULL_VALUE(parser),
.value = value
};
@@ -4846,9 +5067,9 @@ pm_instance_variable_operator_write_node_create(pm_parser_t *parser, pm_instance
},
.name = target->name,
.name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
+ .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
.value = value,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
+ .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
};
return node;
@@ -4923,6 +5144,50 @@ pm_instance_variable_write_node_create(pm_parser_t *parser, pm_instance_variable
}
/**
+ * Append a part into a list of string parts. Importantly this handles nested
+ * interpolated strings by not necessarily removing the marker for static
+ * literals.
+ */
+static void
+pm_interpolated_node_append(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);
+ break;
+ case PM_EMBEDDED_STATEMENTS_NODE: {
+ pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
+ pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
+
+ if (embedded == NULL) {
+ // If there are no statements or more than one statement, then
+ // we lose the static literal flag.
+ pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
+ } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
+ // If the embedded statement is a string, then we can keep the
+ // static literal flag and mark the string as frozen.
+ pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
+ } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
+ // If the embedded statement is an interpolated string and it's
+ // a static literal, then we can keep the static literal flag.
+ } else {
+ // Otherwise we lose the static literal flag.
+ pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
+ }
+
+ break;
+ }
+ case PM_EMBEDDED_VARIABLE_NODE:
+ pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
+ break;
+ default:
+ assert(false && "unexpected node type");
+ break;
+ }
+
+ pm_node_list_append(parts, part);
+}
+
+/**
* Allocate a new InterpolatedRegularExpressionNode node.
*/
static pm_interpolated_regular_expression_node_t *
@@ -4955,54 +5220,113 @@ pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expressio
node->base.location.end = part->location.end;
}
- if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
- pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
- }
-
- if (!PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
- pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
- }
-
- pm_node_list_append(&node->parts, part);
+ pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
}
static 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));
+ pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
}
/**
* Append a part to an InterpolatedStringNode node.
+ *
+ * This has some somewhat complicated semantics, because we need to update
+ * multiple flags that have somewhat confusing interactions.
+ *
+ * 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,
+ * depending on the combination of `--enable-frozen-string-literal`,
+ * `# frozen_string_literal: true`, and whether or not there is interpolation.
+ *
+ * PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN indicates that the string should be
+ * explicitly frozen. This will only happen if the string is comprised entirely
+ * of string parts that are themselves static literals and frozen.
+ *
+ * PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE indicates that the string should
+ * be explicitly marked as mutable. This will happen from
+ * `--disable-frozen-string-literal` or `# frozen_string_literal: false`. This
+ * 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_parser_t *parser, pm_interpolated_string_node_t *node, pm_node_t *part) {
+pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
+#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))
+
+#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);
+
if (node->parts.size == 0 && node->opening_loc.start == NULL) {
node->base.location.start = part->location.start;
}
- if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
- pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
- }
+ node->base.location.end = MAX(node->base.location.end, part->location.end);
- if (!PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
- pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE);
+ switch (PM_NODE_TYPE(part)) {
+ case PM_STRING_NODE:
+ pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
+ break;
+ case PM_INTERPOLATED_STRING_NODE:
+ if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
+ // If the string that we're concatenating is a static literal,
+ // then we can keep the static literal flag for this string.
+ } else {
+ // Otherwise, we lose the static literal flag here and we should
+ // also clear the mutability flags.
+ CLEAR_FLAGS(node);
+ }
+ break;
+ case PM_EMBEDDED_STATEMENTS_NODE: {
+ pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
+ pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
+
+ if (embedded == NULL) {
+ // If we're embedding multiple statements or no statements, then
+ // the string is not longer a static literal.
+ CLEAR_FLAGS(node);
+ } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
+ // If the embedded statement is a string, then we can make that
+ // string as frozen and static literal, and not touch the static
+ // literal status of this string.
+ pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
+
+ if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
+ MUTABLE_FLAGS(node);
+ }
+ } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
+ // If the embedded statement is an interpolated string, but that
+ // string is marked as static literal, then we can keep our
+ // static literal status for this string.
+ if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
+ MUTABLE_FLAGS(node);
+ }
+ } else {
+ // In all other cases, we lose the static literal flag here and
+ // become mutable.
+ CLEAR_FLAGS(node);
+ }
+
+ break;
+ }
+ case PM_EMBEDDED_VARIABLE_NODE:
+ // Embedded variables clear static literal, which means we also
+ // should clear the mutability flags.
+ CLEAR_FLAGS(node);
+ break;
+ default:
+ assert(false && "unexpected node type");
+ break;
}
pm_node_list_append(&node->parts, part);
- node->base.location.end = MAX(node->base.location.end, part->location.end);
- if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
- switch (parser->frozen_string_literal) {
- case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
- pm_node_flag_set((pm_node_t *) node, PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE);
- break;
- case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
- pm_node_flag_set((pm_node_t *) node, PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
- break;
- }
- }
+#undef CLEAR_FLAGS
+#undef MUTABLE_FLAGS
}
/**
@@ -5011,11 +5335,21 @@ pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_n
static pm_interpolated_string_node_t *
pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
pm_interpolated_string_node_t *node = PM_ALLOC_NODE(parser, pm_interpolated_string_node_t);
+ pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
+
+ switch (parser->frozen_string_literal) {
+ case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
+ flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
+ break;
+ case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
+ flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
+ break;
+ }
*node = (pm_interpolated_string_node_t) {
{
.type = PM_INTERPOLATED_STRING_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
+ .flags = flags,
.location = {
.start = opening->start,
.end = closing->end,
@@ -5029,7 +5363,7 @@ pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *openin
if (parts != NULL) {
pm_node_t *part;
PM_NODE_LIST_FOREACH(parts, index, part) {
- pm_interpolated_string_node_append(parser, node, part);
+ pm_interpolated_string_node_append(node, part);
}
}
@@ -5051,15 +5385,7 @@ pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_
node->base.location.start = part->location.start;
}
- if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
- pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
- }
-
- if (!PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
- pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
- }
-
- pm_node_list_append(&node->parts, part);
+ pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
node->base.location.end = MAX(node->base.location.end, part->location.end);
}
@@ -5125,11 +5451,7 @@ pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *openi
static inline void
pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
- if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
- pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
- }
-
- pm_node_list_append(&node->parts, part);
+ pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
node->base.location.end = part->location.end;
}
@@ -5341,10 +5663,10 @@ pm_local_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *tar
}
},
.name_loc = target->location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
+ .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
.value = value,
.name = name,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
+ .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
.depth = depth
};
@@ -6397,6 +6719,7 @@ pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_argumen
*node = (pm_return_node_t) {
{
.type = PM_RETURN_NODE,
+ .flags = 0,
.location = {
.start = keyword->start,
.end = (arguments == NULL ? keyword->end : arguments->base.location.end)
@@ -6622,7 +6945,7 @@ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node,
case PM_REDO_NODE:
case PM_RETRY_NODE:
case PM_RETURN_NODE:
- pm_parser_warn_node(parser, previous, PM_WARN_UNREACHABLE_STATEMENT);
+ pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
break;
default:
break;
@@ -6729,7 +7052,8 @@ pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_argument
}
/**
- * Read through the contents of a string and check if it consists solely of US ASCII code points.
+ * Read through the contents of a string and check if it consists solely of
+ * US-ASCII code points.
*/
static bool
pm_ascii_only_p(const pm_string_t *contents) {
@@ -6744,26 +7068,71 @@ pm_ascii_only_p(const pm_string_t *contents) {
}
/**
+ * Validate that the contents of the given symbol are all valid UTF-8.
+ */
+static void
+parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
+ for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
+ 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);
+ break;
+ }
+
+ cursor += width;
+ }
+}
+
+/**
+ * Validate that the contents of the given symbol are all valid in the encoding
+ * of the parser.
+ */
+static void
+parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
+ const pm_encoding_t *encoding = parser->encoding;
+
+ for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
+ size_t width = encoding->char_width(cursor, end - cursor);
+
+ if (width == 0) {
+ pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
+ break;
+ }
+
+ cursor += width;
+ }
+}
+
+/**
* Ruby "downgrades" the encoding of Symbols to US-ASCII if the associated
* encoding is ASCII-compatible and the Symbol consists only of US-ASCII code
* points. Otherwise, the encoding may be explicitly set with an escape
* sequence.
+ *
+ * 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
-parse_symbol_encoding(const pm_parser_t *parser, const pm_string_t *contents) {
+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
// happen if an escape sequence results in a non-ASCII code point.
if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
+ if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
} else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
+ } else if (validate) {
+ parse_symbol_encoding_validate_other(parser, location, contents);
}
} else if (pm_ascii_only_p(contents)) {
// Ruby stipulates that all source files must use an ASCII-compatible
// encoding. Thus, all symbols appearing in source are eligible for
// "downgrading" to US-ASCII.
return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
+ } else if (validate) {
+ parse_symbol_encoding_validate_other(parser, location, contents);
}
return 0;
@@ -6931,7 +7300,7 @@ pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_t
*/
static pm_symbol_node_t *
pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
- pm_symbol_node_t *node = pm_symbol_node_create_unescaped(parser, opening, value, closing, &parser->current_string, parse_symbol_encoding(parser, &parser->current_string));
+ pm_symbol_node_t *node = pm_symbol_node_create_unescaped(parser, opening, value, closing, &parser->current_string, parse_symbol_encoding(parser, value, &parser->current_string, false));
parser->current_string = PM_STRING_EMPTY;
return node;
}
@@ -6953,7 +7322,7 @@ pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
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, &node->unescaped));
+ pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
break;
}
@@ -6985,9 +7354,9 @@ pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
{
.type = PM_SYMBOL_NODE,
.flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
- .location = { .start = parser->start, .end = parser->start }
+ .location = PM_LOCATION_NULL_VALUE(parser)
},
- .value_loc = { .start = parser->start, .end = parser->start },
+ .value_loc = PM_LOCATION_NULL_VALUE(parser),
.unescaped = { 0 }
};
@@ -7038,7 +7407,8 @@ pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const
.unescaped = node->unescaped
};
- pm_node_flag_set((pm_node_t *)new_node, parse_symbol_encoding(parser, &node->unescaped));
+ 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
@@ -7387,10 +7757,10 @@ pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_s
*node = (pm_while_node_t) {
{
.type = PM_WHILE_NODE,
- .location = { .start = parser->start, .end = parser->start }
+ .location = PM_LOCATION_NULL_VALUE(parser)
},
- .keyword_loc = { .start = parser->start, .end = parser->start },
- .closing_loc = { .start = parser->start, .end = parser->start },
+ .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
+ .closing_loc = PM_LOCATION_NULL_VALUE(parser),
.predicate = predicate,
.statements = statements
};
@@ -7574,7 +7944,7 @@ pm_local_variable_read_node_create_it(pm_parser_t *parser, const pm_token_t *nam
static pm_node_t *
pm_node_check_it(pm_parser_t *parser, pm_node_t *node) {
if (
- (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3_0) &&
+ (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) &&
!parser->current_scope->closed &&
(parser->current_scope->numbered_parameters != PM_SCOPE_NUMBERED_PARAMETERS_DISALLOWED) &&
pm_node_is_it(parser, node)
@@ -8023,7 +8393,12 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
// If we have hit a ractor pragma, attempt to lex that.
uint32_t value_length = (uint32_t) (value_end - value_start);
if (key_length == 24 && pm_strncasecmp(key_source, (const uint8_t *) "shareable_constant_value", 24) == 0) {
- if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "none", 4) == 0) {
+ const uint8_t *cursor = parser->current.start;
+ while ((cursor > parser->start) && ((cursor[-1] == ' ') || (cursor[-1] == '\t'))) cursor--;
+
+ if (!((cursor == parser->start) || (cursor[-1] == '\n'))) {
+ pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
+ } else if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "none", 4) == 0) {
pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
} else if (value_length == 7 && pm_strncasecmp(value_start, (const uint8_t *) "literal", 7) == 0) {
pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
@@ -8298,10 +8673,11 @@ context_human(pm_context_t context) {
/* Specific token lexers */
/******************************************************************************/
-static void
-pm_strspn_number_validate(pm_parser_t *parser, const uint8_t *invalid) {
+static 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_parser_err(parser, invalid, invalid + 1, PM_ERR_INVALID_NUMBER_UNDERSCORE);
+ 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);
}
}
@@ -8309,7 +8685,7 @@ static size_t
pm_strspn_binary_number_validate(pm_parser_t *parser, const uint8_t *string) {
const uint8_t *invalid = NULL;
size_t length = pm_strspn_binary_number(string, parser->end - string, &invalid);
- pm_strspn_number_validate(parser, invalid);
+ pm_strspn_number_validate(parser, string, length, invalid);
return length;
}
@@ -8317,7 +8693,7 @@ static size_t
pm_strspn_octal_number_validate(pm_parser_t *parser, const uint8_t *string) {
const uint8_t *invalid = NULL;
size_t length = pm_strspn_octal_number(string, parser->end - string, &invalid);
- pm_strspn_number_validate(parser, invalid);
+ pm_strspn_number_validate(parser, string, length, invalid);
return length;
}
@@ -8325,7 +8701,7 @@ static size_t
pm_strspn_decimal_number_validate(pm_parser_t *parser, const uint8_t *string) {
const uint8_t *invalid = NULL;
size_t length = pm_strspn_decimal_number(string, parser->end - string, &invalid);
- pm_strspn_number_validate(parser, invalid);
+ pm_strspn_number_validate(parser, string, length, invalid);
return length;
}
@@ -8333,7 +8709,7 @@ static size_t
pm_strspn_hexadecimal_number_validate(pm_parser_t *parser, const uint8_t *string) {
const uint8_t *invalid = NULL;
size_t length = pm_strspn_hexadecimal_number(string, parser->end - string, &invalid);
- pm_strspn_number_validate(parser, invalid);
+ pm_strspn_number_validate(parser, string, length, invalid);
return length;
}
@@ -8395,6 +8771,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
if (pm_char_is_decimal_digit(peek(parser))) {
parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
} else {
+ match(parser, '_');
pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
}
@@ -8407,6 +8784,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
if (pm_char_is_binary_digit(peek(parser))) {
parser->current.end += pm_strspn_binary_number_validate(parser, parser->current.end);
} else {
+ match(parser, '_');
pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
}
@@ -8420,6 +8798,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
if (pm_char_is_octal_digit(peek(parser))) {
parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
} else {
+ match(parser, '_');
pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
}
@@ -8447,6 +8826,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
if (pm_char_is_hexadecimal_digit(peek(parser))) {
parser->current.end += pm_strspn_hexadecimal_number_validate(parser, parser->current.end);
} else {
+ match(parser, '_');
pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
}
@@ -8475,6 +8855,16 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
type = lex_optional_float_suffix(parser, seen_e);
}
+ // At this point we have a completed number, but we want to provide the user
+ // with a good experience if they put an additional .xxx fractional
+ // component on the end, so we'll check for that here.
+ if (peek_offset(parser, 0) == '.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
+ 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);
+ }
+
return type;
}
@@ -8567,7 +8957,7 @@ lex_global_variable(pm_parser_t *parser) {
} while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0);
// $0 isn't allowed to be followed by anything.
- pm_diagnostic_id_t diag_id = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3_0 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3_0 : PM_ERR_INVALID_VARIABLE_GLOBAL;
+ 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);
}
@@ -8603,9 +8993,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_0 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3_0 : PM_ERR_INVALID_VARIABLE_GLOBAL;
- size_t width = parser->encoding->char_width(parser->current.end, parser->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_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);
}
return PM_TOKEN_GLOBAL_VARIABLE;
@@ -8976,12 +9366,20 @@ escape_hexadecimal_digit(const uint8_t value) {
* validated.
*/
static inline uint32_t
-escape_unicode(const uint8_t *string, size_t length) {
+escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length) {
uint32_t value = 0;
for (size_t index = 0; index < length; index++) {
if (index != 0) value <<= 4;
value |= escape_hexadecimal_digit(string[index]);
}
+
+ // 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);
+ return 0xFFFD;
+ }
+
return value;
}
@@ -9230,7 +9628,7 @@ 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));
}
- escape_write_byte_encoded(parser, buffer, value);
+ escape_write_byte_encoded(parser, buffer, escape_byte(value, flags));
} else {
pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
}
@@ -9241,22 +9639,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
const uint8_t *start = parser->current.end - 1;
parser->current.end++;
- if (
- (parser->current.end + 4 <= parser->end) &&
- pm_char_is_hexadecimal_digit(parser->current.end[0]) &&
- pm_char_is_hexadecimal_digit(parser->current.end[1]) &&
- pm_char_is_hexadecimal_digit(parser->current.end[2]) &&
- pm_char_is_hexadecimal_digit(parser->current.end[3])
- ) {
- uint32_t value = escape_unicode(parser->current.end, 4);
-
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end + 4 - start));
- }
- escape_write_unicode(parser, buffer, flags, start, parser->current.end + 4, value);
-
- parser->current.end += 4;
- } else if (peek(parser) == '{') {
+ if (peek(parser) == '{') {
const uint8_t *unicode_codepoints_start = parser->current.end - 2;
parser->current.end++;
@@ -9274,7 +9657,8 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
} else if (hexadecimal_length == 0) {
// there are not hexadecimal characters
- pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE);
+ 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);
return;
}
@@ -9284,7 +9668,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(unicode_start, hexadecimal_length);
+ uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
parser->current.end += pm_strspn_whitespace(parser->current.end, parser->end - parser->current.end);
@@ -9306,7 +9690,21 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (size_t) (parser->current.end - unicode_codepoints_start));
}
} else {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
+ size_t length = pm_strspn_hexadecimal_digit(parser->current.end, MIN(parser->end - parser->current.end, 4));
+
+ if (length == 4) {
+ uint32_t value = escape_unicode(parser, parser->current.end, 4);
+
+ if (flags & PM_ESCAPE_FLAG_REGEXP) {
+ pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end + 4 - start));
+ }
+
+ escape_write_unicode(parser, buffer, flags, start, parser->current.end + 4, value);
+ parser->current.end += 4;
+ } else {
+ parser->current.end += length;
+ pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
+ }
}
return;
@@ -9331,6 +9729,12 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
return;
}
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);
+ return;
+ }
+
escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
return;
case ' ':
@@ -9358,7 +9762,8 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
case 'C': {
parser->current.end++;
if (peek(parser) != '-') {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
+ 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);
return;
}
@@ -9381,6 +9786,12 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
return;
}
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);
+ return;
+ }
+
escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
return;
case ' ':
@@ -9395,7 +9806,8 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
return;
default: {
if (!char_is_ascii_printable(peeked)) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
+ 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);
return;
}
@@ -9408,7 +9820,8 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
case 'M': {
parser->current.end++;
if (peek(parser) != '-') {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
+ 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);
return;
}
@@ -9426,6 +9839,12 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
return;
}
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);
+ return;
+ }
+
escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
return;
case ' ':
@@ -9440,7 +9859,8 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
return;
default:
if (!char_is_ascii_printable(peeked)) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
+ 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);
return;
}
@@ -9560,8 +9980,8 @@ lex_at_variable(pm_parser_t *parser) {
}
} else if (parser->current.end < parser->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_0) {
- diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3_0 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3_0;
+ 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, parser->end - parser->current.end);
@@ -10545,8 +10965,11 @@ parser_lex(pm_parser_t *parser) {
}
size_t ident_length = (size_t) (parser->current.end - ident_start);
+ bool ident_error = false;
+
if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
- // TODO: handle unterminated heredoc
+ pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
+ ident_error = true;
}
parser->explicit_encoding = NULL;
@@ -10571,7 +10994,7 @@ parser_lex(pm_parser_t *parser) {
// this is not a valid heredoc declaration. In this case we
// will add an error, but we will still return a heredoc
// start.
- pm_parser_err_current(parser, PM_ERR_HEREDOC_TERM);
+ if (!ident_error) pm_parser_err_heredoc_term(parser, parser->lex_modes.current);
body_start = parser->end;
} else {
// Otherwise, we want to indicate that the body of the
@@ -10951,7 +11374,7 @@ parser_lex(pm_parser_t *parser) {
// operator because we don't want to move into the string
// lex mode unnecessarily.
if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) {
- pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
+ pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
LEX(PM_TOKEN_PERCENT);
}
@@ -10970,10 +11393,7 @@ parser_lex(pm_parser_t *parser) {
const uint8_t delimiter = pm_lex_percent_delimiter(parser);
lex_mode_push_string(parser, true, false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
-
- if (parser->current.end < parser->end) {
- LEX(PM_TOKEN_STRING_BEGIN);
- }
+ LEX(PM_TOKEN_STRING_BEGIN);
}
// Delimiters for %-literals cannot be alphanumeric. We
@@ -11898,7 +12318,7 @@ parser_lex(pm_parser_t *parser) {
// terminator) but still continue parsing so that content after the
// declaration of the heredoc can be parsed.
if (parser->current.end >= parser->end) {
- pm_parser_err_current(parser, PM_ERR_HEREDOC_TERM);
+ pm_parser_err_heredoc_term(parser, lex_mode);
parser->next_start = lex_mode->as.heredoc.next_start;
parser->heredoc_end = parser->current.end;
lex_state_set(parser, PM_LEX_STATE_END);
@@ -12537,6 +12957,23 @@ expect3(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_to
parser->previous.type = PM_TOKEN_MISSING;
}
+/**
+ * A special expect1 that expects a heredoc terminator and handles popping the
+ * lex mode accordingly.
+ */
+static void
+expect1_heredoc_term(pm_parser_t *parser, pm_lex_mode_t *lex_mode) {
+ if (match1(parser, PM_TOKEN_HEREDOC_END)) {
+ lex_mode_pop(parser);
+ parser_lex(parser);
+ } else {
+ pm_parser_err_heredoc_term(parser, lex_mode);
+ lex_mode_pop(parser);
+ parser->previous.start = parser->previous.end;
+ parser->previous.type = PM_TOKEN_MISSING;
+ }
+}
+
static pm_node_t *
parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id);
@@ -12665,24 +13102,71 @@ parse_write_name(pm_parser_t *parser, pm_constant_id_t *name_field) {
}
/**
+ * Certain expressions are not targetable, but in order to provide a better
+ * experience we give a specific error message. In order to maintain as much
+ * information in the tree as possible, we replace them with local variable
+ * writes.
+ */
+static pm_node_t *
+parse_unwriteable_target(pm_parser_t *parser, pm_node_t *target) {
+ switch (PM_NODE_TYPE(target)) {
+ case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING); break;
+ case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE); break;
+ case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE); break;
+ case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE); break;
+ case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL); break;
+ case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF); break;
+ case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE); break;
+ default: break;
+ }
+
+ pm_constant_id_t name = pm_parser_constant_id_location(parser, target->location.start, target->location.end);
+ 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;
+}
+
+/**
* Convert the given node into a valid target node.
*/
static pm_node_t *
-parse_target(pm_parser_t *parser, pm_node_t *target) {
+parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple) {
switch (PM_NODE_TYPE(target)) {
case PM_MISSING_NODE:
return target;
+ case PM_SOURCE_ENCODING_NODE:
+ case PM_FALSE_NODE:
+ case PM_SOURCE_FILE_NODE:
+ case PM_SOURCE_LINE_NODE:
+ case PM_NIL_NODE:
+ case PM_SELF_NODE:
+ case PM_TRUE_NODE: {
+ // In these special cases, we have specific error messages and we
+ // will replace them with local variable writes.
+ return parse_unwriteable_target(parser, target);
+ }
case PM_CLASS_VARIABLE_READ_NODE:
assert(sizeof(pm_class_variable_target_node_t) == sizeof(pm_class_variable_read_node_t));
target->type = PM_CLASS_VARIABLE_TARGET_NODE;
return target;
case PM_CONSTANT_PATH_NODE:
+ if (context_def_p(parser)) {
+ pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
+ }
+
assert(sizeof(pm_constant_path_target_node_t) == sizeof(pm_constant_path_node_t));
target->type = PM_CONSTANT_PATH_TARGET_NODE;
+
return target;
case PM_CONSTANT_READ_NODE:
+ if (context_def_p(parser)) {
+ pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
+ }
+
assert(sizeof(pm_constant_target_node_t) == sizeof(pm_constant_read_node_t));
target->type = PM_CONSTANT_TARGET_NODE;
+
return target;
case PM_BACK_REFERENCE_READ_NODE:
case PM_NUMBERED_REFERENCE_READ_NODE:
@@ -12715,7 +13199,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target) {
pm_splat_node_t *splat = (pm_splat_node_t *) target;
if (splat->expression != NULL) {
- splat->expression = parse_target(parser, splat->expression);
+ splat->expression = parse_target(parser, splat->expression, multiple);
}
return (pm_node_t *) splat;
@@ -12753,6 +13237,10 @@ parse_target(pm_parser_t *parser, pm_node_t *target) {
}
if (*call->message_loc.start == '_' || parser->encoding->alnum_char(call->message_loc.start, call->message_loc.end - call->message_loc.start)) {
+ 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);
}
@@ -12780,8 +13268,8 @@ parse_target(pm_parser_t *parser, pm_node_t *target) {
* assignment.
*/
static pm_node_t *
-parse_target_validate(pm_parser_t *parser, pm_node_t *target) {
- pm_node_t *result = parse_target(parser, target);
+parse_target_validate(pm_parser_t *parser, pm_node_t *target, bool multiple) {
+ pm_node_t *result = parse_target(parser, target, multiple);
// Ensure that we have one of an =, an 'in' in for indexes, and a ')' in parens after the targets.
if (
@@ -12826,13 +13314,20 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
}
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);
+
+ if (context_def_p(parser)) {
+ pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
+ }
+
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);
+
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);
}
@@ -13011,7 +13506,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
pm_multi_target_node_t *result = pm_multi_target_node_create(parser);
- pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target));
+ pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target, true));
while (accept1(parser, PM_TOKEN_COMMA)) {
if (accept1(parser, PM_TOKEN_USTAR)) {
@@ -13027,7 +13522,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
if (token_begins_expression_p(parser->current.type)) {
name = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
- name = parse_target(parser, name);
+ name = parse_target(parser, name, true);
}
pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
@@ -13035,7 +13530,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
has_rest = true;
} else if (token_begins_expression_p(parser->current.type)) {
pm_node_t *target = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA);
- target = parse_target(parser, target);
+ target = parse_target(parser, target, true);
pm_multi_target_node_targets_append(parser, result, target);
} else if (!match1(parser, PM_TOKEN_EOF)) {
@@ -13072,8 +13567,8 @@ parse_targets_validate(pm_parser_t *parser, pm_node_t *first_target, pm_binding_
*/
static pm_statements_node_t *
parse_statements(pm_parser_t *parser, pm_context_t context) {
- // First, skip past any optional terminators that might be at the beginning of
- // the statements.
+ // First, skip past any optional terminators that might be at the beginning
+ // of the statements.
while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
// If we have a terminator, then we can just return NULL.
@@ -13089,20 +13584,20 @@ parse_statements(pm_parser_t *parser, pm_context_t context) {
pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_CANNOT_PARSE_EXPRESSION);
pm_statements_node_body_append(parser, statements, node);
- // If we're recovering from a syntax error, then we need to stop parsing the
- // statements now.
+ // 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 this is the level of context where the recovery has happened,
+ // then we can mark the parser as done recovering.
if (context_terminator(context, &parser->current)) parser->recovering = false;
break;
}
- // If we have a terminator, then we will parse all consecutive terminators
- // and then continue parsing the statements list.
+ // If we have a terminator, then we will parse all consecutive
+ // terminators and then continue parsing the statements list.
if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- // If we have a terminator, then we will continue parsing the statements
- // list.
+ // If we have a terminator, then we will continue parsing the
+ // statements list.
while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
if (context_terminator(context, &parser->current)) break;
@@ -13110,27 +13605,28 @@ parse_statements(pm_parser_t *parser, pm_context_t context) {
continue;
}
- // At this point we have a list of statements that are not terminated by a
- // newline or semicolon. At this point we need to check if we're at the end
- // of the statements list. If we are, then we should break out of the loop.
+ // At this point we have a list of statements that are not terminated by
+ // a newline or semicolon. At this point we need to check if we're at
+ // the end of the statements list. If we are, then we should break out
+ // of the loop.
if (context_terminator(context, &parser->current)) break;
// At this point, we have a syntax error, because the statement was not
// terminated by a newline or semicolon, and we're not at the end of the
- // statements list. Ideally we should scan forward to determine if we should
- // insert a missing terminator or break out of parsing the statements list
- // at this point.
+ // statements list. Ideally we should scan forward to determine if we
+ // should insert a missing terminator or break out of parsing the
+ // statements list at this point.
//
- // We don't have that yet, so instead we'll do a more naive approach. If we
- // were unable to parse an expression, then we will skip past this token and
- // continue parsing the statements list. Otherwise we'll add an error and
- // continue parsing the statements list.
+ // We don't have that yet, so instead we'll do a more naive approach. If
+ // we were unable to parse an expression, then we will skip past this
+ // token and continue parsing the statements list. Otherwise we'll add
+ // an error and continue parsing the statements list.
if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
parser_lex(parser);
while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
if (context_terminator(context, &parser->current)) break;
- } else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
+ } else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
// 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.
@@ -13152,11 +13648,11 @@ parse_statements(pm_parser_t *parser, pm_context_t context) {
*/
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, literals, node);
+ const pm_node_t *duplicated = pm_static_literals_add(&parser->newline_list, parser->start_line, literals, node);
if (duplicated != NULL) {
pm_buffer_t buffer = { 0 };
- pm_static_literal_inspect(&buffer, parser, duplicated);
+ pm_static_literal_inspect(&buffer, &parser->newline_list, parser->start_line, parser->encoding->name, duplicated);
pm_diagnostic_list_append_format(
&parser->warning_list,
@@ -13178,7 +13674,7 @@ pm_hash_key_static_literals_add(pm_parser_t *parser, pm_static_literals_t *liter
*/
static void
pm_when_clause_static_literals_add(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node) {
- if (pm_static_literals_add(parser, literals, node) != NULL) {
+ if (pm_static_literals_add(&parser->newline_list, parser->start_line, literals, node) != NULL) {
pm_diagnostic_list_append_format(
&parser->warning_list,
node->location.start,
@@ -13206,10 +13702,16 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod
pm_token_t operator = parser->previous;
pm_node_t *value = NULL;
- if (token_begins_expression_p(parser->current.type)) {
+ if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
+ // If we're about to parse a nested hash that is being
+ // pushed into this hash directly with **, then we want the
+ // 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, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH);
- }
- else {
+ } else if (token_begins_expression_p(parser->current.type)) {
+ value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH);
+ } else {
pm_parser_scope_forwarding_keywords_check(parser, &operator);
}
@@ -13234,9 +13736,15 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod
pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.start, .end = label.end - 1 };
value = (pm_node_t *) pm_constant_read_node_create(parser, &constant);
} else {
- int depth = pm_parser_local_depth(parser, &((pm_token_t) { .type = PM_TOKEN_IDENTIFIER, .start = label.start, .end = label.end - 1 }));
+ 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);
+ } else {
+ depth = pm_parser_local_depth(parser, &identifier);
+ }
+
if (depth == -1) {
value = (pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
} else {
@@ -13354,15 +13862,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;
- pm_static_literals_t literals = { 0 };
- bool contains_keyword_splat = parse_assocs(parser, &literals, (pm_node_t *) hash);
+ pm_static_literals_t hash_keys = { 0 };
+ bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (pm_node_t *) hash);
parse_arguments_append(parser, arguments, argument);
- if (contains_keyword_splat) {
- pm_node_flag_set((pm_node_t *)arguments->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT);
- }
- pm_static_literals_free(&literals);
+ 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_static_literals_free(&hash_keys);
parsed_bare_hash = true;
break;
@@ -13438,7 +13947,9 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument, PM_ERR_EXPECT_ARGUMENT);
}
+ bool contains_keywords = false;
bool contains_keyword_splat = false;
+
if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
if (parsed_bare_hash) {
pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
@@ -13452,10 +13963,11 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
}
pm_keyword_hash_node_t *bare_hash = pm_keyword_hash_node_create(parser);
+ contains_keywords = true;
// Create the set of static literals for this hash.
- pm_static_literals_t literals = { 0 };
- pm_hash_key_static_literals_add(parser, &literals, argument);
+ pm_static_literals_t hash_keys = { 0 };
+ 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, PM_ERR_HASH_VALUE);
@@ -13469,10 +13981,10 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
token_begins_expression_p(parser->current.type) ||
match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
)) {
- contains_keyword_splat = parse_assocs(parser, &literals, (pm_node_t *) bare_hash);
+ contains_keyword_splat = parse_assocs(parser, &hash_keys, (pm_node_t *) bare_hash);
}
- pm_static_literals_free(&literals);
+ pm_static_literals_free(&hash_keys);
parsed_bare_hash = true;
} else if (accept1(parser, PM_TOKEN_KEYWORD_IN)) {
// TODO: Could we solve this with binding powers instead?
@@ -13480,9 +13992,12 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
}
parse_arguments_append(parser, arguments, argument);
- if (contains_keyword_splat) {
- pm_node_flag_set((pm_node_t *)arguments->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT);
- }
+
+ 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);
+
break;
}
}
@@ -13595,7 +14110,6 @@ typedef enum {
PM_PARAMETERS_ORDER_OPTIONAL,
PM_PARAMETERS_ORDER_NAMED,
PM_PARAMETERS_ORDER_NONE,
-
} pm_parameters_order_t;
/**
@@ -13620,31 +14134,37 @@ static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
* Check if current parameter follows valid parameters ordering. If not it adds
* an error to the list without stopping the parsing, otherwise sets the
* parameters state to the one corresponding to the current parameter.
+ *
+ * It returns true if it was successful, and false otherwise.
*/
-static void
+static bool
update_parameter_state(pm_parser_t *parser, pm_token_t *token, pm_parameters_order_t *current) {
pm_parameters_order_t state = parameters_ordering[token->type];
- if (state == PM_PARAMETERS_NO_CHANGE) return;
+ if (state == PM_PARAMETERS_NO_CHANGE) return true;
// If we see another ordered argument after a optional argument
// we only continue parsing ordered arguments until we stop seeing ordered arguments.
if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
*current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
- return;
+ return true;
} else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
- return;
+ return true;
}
if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
- }
-
- if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
+ return false;
+ } else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
+ pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
+ return false;
+ } else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
// We know what transition we failed on, so we can provide a better error here.
pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
- } else if (state < *current) {
- *current = state;
+ return false;
}
+
+ if (state < *current) *current = state;
+ return true;
}
/**
@@ -13713,27 +14233,22 @@ parse_parameters(
pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
}
- if (order > PM_PARAMETERS_ORDER_NOTHING_AFTER) {
- update_parameter_state(parser, &parser->current, &order);
- parser_lex(parser);
+ bool succeeded = update_parameter_state(parser, &parser->current, &order);
+ parser_lex(parser);
- parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
+ parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
+ pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->previous);
- pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->previous);
- if (params->keyword_rest != NULL) {
- // If we already have a keyword rest parameter, then we replace it with the
- // forwarding parameter and move the keyword rest parameter to the posts list.
- pm_node_t *keyword_rest = params->keyword_rest;
- pm_parameters_node_posts_append(params, keyword_rest);
- pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
- params->keyword_rest = NULL;
- }
- pm_parameters_node_keyword_rest_set(params, (pm_node_t *)param);
- } else {
- update_parameter_state(parser, &parser->current, &order);
- parser_lex(parser);
+ if (params->keyword_rest != NULL) {
+ // If we already have a keyword rest parameter, then we replace it with the
+ // forwarding parameter and move the keyword rest parameter to the posts list.
+ pm_node_t *keyword_rest = params->keyword_rest;
+ pm_parameters_node_posts_append(params, keyword_rest);
+ 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);
break;
}
case PM_TOKEN_CLASS_VARIABLE:
@@ -13828,6 +14343,12 @@ parse_parameters(
pm_token_t local = name;
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);
+ } else if (local.end[-1] == '!' || local.end[-1] == '?') {
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
+ }
+
bool repeated = pm_parser_parameter_name_check(parser, &local);
pm_parser_local_add_token(parser, &local, 1);
@@ -13903,6 +14424,7 @@ parse_parameters(
pm_token_t operator = parser->previous;
pm_token_t name;
bool repeated = false;
+
if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
name = parser->previous;
repeated = pm_parser_parameter_name_check(parser, &name);
@@ -13916,6 +14438,7 @@ parse_parameters(
if (repeated) {
pm_node_flag_set_repeated_parameter(param);
}
+
if (params->rest == NULL) {
pm_parameters_node_rest_set(params, param);
} else {
@@ -13927,6 +14450,7 @@ parse_parameters(
}
case PM_TOKEN_STAR_STAR:
case PM_TOKEN_USTAR_STAR: {
+ pm_parameters_order_t previous_order = order;
update_parameter_state(parser, &parser->current, &order);
parser_lex(parser);
@@ -13934,6 +14458,10 @@ parse_parameters(
pm_node_t *param;
if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
+ if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
+ 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);
} else {
pm_token_t name;
@@ -14031,7 +14559,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, pm_rescues_type
pm_rescue_node_operator_set(rescue, &parser->previous);
pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_RESCUE_VARIABLE);
- reference = parse_target(parser, reference);
+ reference = parse_target(parser, reference, false);
pm_rescue_node_reference_set(rescue, reference);
break;
@@ -14061,7 +14589,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, pm_rescues_type
pm_rescue_node_operator_set(rescue, &parser->previous);
pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_RESCUE_VARIABLE);
- reference = parse_target(parser, reference);
+ reference = parse_target(parser, reference, false);
pm_rescue_node_reference_set(rescue, reference);
break;
@@ -14385,7 +14913,7 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
} else {
pm_accepts_block_stack_push(parser, true);
- parse_arguments(parser, arguments, true, PM_TOKEN_PARENTHESIS_RIGHT);
+ parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT);
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));
@@ -14403,7 +14931,7 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
// If we get here, then the subsequent token cannot be used as an infix
// operator. In this case we assume the subsequent token is part of an
// argument to this method call.
- parse_arguments(parser, arguments, true, PM_TOKEN_EOF);
+ parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF);
// If we have done with the arguments and still not consumed the comma,
// then we have a trailing comma where we need to check whether it is
@@ -14434,11 +14962,8 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
if (arguments->block == NULL && !arguments->has_forwarding) {
arguments->block = (pm_node_t *) block;
} else {
- if (arguments->has_forwarding) {
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_FORWARDING);
- } else {
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
- }
+ pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
+
if (arguments->block != NULL) {
if (arguments->arguments == NULL) {
arguments->arguments = pm_arguments_node_create(parser);
@@ -14875,6 +15400,10 @@ parse_string_part(pm_parser_t *parser) {
// "aaa #{bbb} #@ccc ddd"
// ^^^^^^
case PM_TOKEN_EMBEXPR_BEGIN: {
+ // Ruby disallows seeing encoding around interpolation in strings,
+ // even though it is known at parse time.
+ parser->explicit_encoding = NULL;
+
pm_lex_state_t state = parser->lex_state;
int brace_nesting = parser->brace_nesting;
@@ -14907,6 +15436,10 @@ parse_string_part(pm_parser_t *parser) {
// "aaa #{bbb} #@ccc ddd"
// ^^^^^
case PM_TOKEN_EMBVAR: {
+ // Ruby disallows seeing encoding around interpolation in strings,
+ // even though it is known at parse time.
+ parser->explicit_encoding = NULL;
+
lex_state_set(parser, PM_LEX_STATE_BEG);
parser_lex(parser);
@@ -15030,7 +15563,7 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, &closing);
pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.end);
- pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &symbol->unescaped));
+ pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
return (pm_node_t *) symbol;
}
@@ -15130,7 +15663,7 @@ 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, &unescaped));
+ return (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, false));
}
/**
@@ -15155,7 +15688,7 @@ parse_undef_argument(pm_parser_t *parser) {
pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, &closing);
pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.end);
- pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &symbol->unescaped));
+ pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
return (pm_node_t *) symbol;
}
@@ -15196,7 +15729,7 @@ parse_alias_argument(pm_parser_t *parser, bool first) {
pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, &closing);
pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.end);
- pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &symbol->unescaped));
+ pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
return (pm_node_t *) symbol;
}
@@ -15423,8 +15956,12 @@ parse_heredoc_dedent(pm_parser_t *parser, pm_node_list_t *nodes, size_t common_w
nodes->size = write_index;
}
+#define PM_PARSE_PATTERN_SINGLE 0
+#define PM_PARSE_PATTERN_TOP 1
+#define PM_PARSE_PATTERN_MULTI 2
+
static pm_node_t *
-parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, bool top_pattern, pm_diagnostic_id_t diag_id);
+parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flags, pm_diagnostic_id_t diag_id);
/**
* Add the newly created local to the list of captures for this pattern matching
@@ -15453,9 +15990,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);
-
- pm_node_t *child = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
- node = (pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, child);
+ node = (pm_node_t *) 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
@@ -15474,7 +16009,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
accept1(parser, PM_TOKEN_NEWLINE);
if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- inner = parse_pattern(parser, captures, true, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET);
+ inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET);
accept1(parser, PM_TOKEN_NEWLINE);
expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
}
@@ -15486,7 +16021,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
accept1(parser, PM_TOKEN_NEWLINE);
if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- inner = parse_pattern(parser, captures, true, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN);
+ inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN);
accept1(parser, PM_TOKEN_NEWLINE);
expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
}
@@ -15635,16 +16170,54 @@ parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures)
}
/**
+ * Check that the slice of the source given by the bounds parameters constitutes
+ * a valid local variable name.
+ */
+static bool
+pm_slice_is_valid_local(const pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
+ ptrdiff_t length = end - start;
+ if (length == 0) return false;
+
+ // First ensure that it starts with a valid identifier starting character.
+ size_t width = char_is_identifier_start(parser, start);
+ if (width == 0) return false;
+
+ // Next, ensure that it's not an uppercase character.
+ if (parser->encoding_changed) {
+ if (parser->encoding->isupper_char(start, length)) return false;
+ } else {
+ if (pm_encoding_utf_8_isupper_char(start, length)) return false;
+ }
+
+ // Next, iterate through all of the bytes of the string to ensure that they
+ // are all valid identifier characters.
+ const uint8_t *cursor = start + width;
+ while ((cursor < end) && (width = char_is_identifier(parser, cursor))) cursor += width;
+ return cursor == end;
+}
+
+/**
* Create an implicit node for the value of a hash pattern that has omitted the
* value. This will use an implicit local variable target.
*/
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;
+
pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, value_loc->start, value_loc->end);
+ int depth = -1;
- int depth;
- if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
+ if (pm_slice_is_valid_local(parser, value_loc->start, value_loc->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);
+
+ 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 (depth == -1) {
pm_parser_local_add(parser, constant_id, value_loc->start, value_loc->end, 0);
}
@@ -15665,7 +16238,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, keys, node) != NULL) {
+ if (pm_static_literals_add(&parser->newline_list, parser->start_line, keys, node) != NULL) {
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
}
}
@@ -15696,7 +16269,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
} else {
// Here we have a value for the first assoc in the list, so
// we will parse it now.
- value = parse_pattern(parser, captures, false, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY);
+ value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY);
}
pm_token_t operator = not_provided(parser);
@@ -15711,7 +16284,8 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
// If we get anything else, then this is an error. For this we'll
// create a missing node for the value and create an assoc node for
// the first node in the list.
- pm_parser_err_node(parser, first_node, PM_ERR_PATTERN_HASH_KEY_LABEL);
+ 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);
@@ -15748,7 +16322,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
if (match7(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key);
} else {
- value = parse_pattern(parser, captures, false, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY);
+ value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY);
}
pm_token_t operator = not_provided(parser);
@@ -15805,7 +16379,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
// Otherwise, we'll parse the inner pattern, then deal with it depending
// on the type it returns.
- pm_node_t *inner = parse_pattern(parser, captures, true, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET);
+ pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET);
accept1(parser, PM_TOKEN_NEWLINE);
expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
@@ -15872,11 +16446,11 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
first_node = parse_pattern_keyword_rest(parser, captures);
break;
case PM_TOKEN_STRING_BEGIN:
- first_node = parse_expression(parser, PM_BINDING_POWER_MAX, false, PM_ERR_PATTERN_HASH_KEY);
+ first_node = parse_expression(parser, PM_BINDING_POWER_MAX, false, PM_ERR_PATTERN_HASH_KEY_LABEL);
break;
default: {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_type_human(parser->current.type));
parser_lex(parser);
- pm_parser_err_previous(parser, PM_ERR_PATTERN_HASH_KEY);
first_node = (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
break;
@@ -15953,7 +16527,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
if (variable == NULL) {
if (
- (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3_0) &&
+ (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) &&
!parser->current_scope->closed &&
(parser->current_scope->numbered_parameters != PM_SCOPE_NUMBERED_PARAMETERS_DISALLOWED) &&
pm_token_is_it(parser->previous.start, parser->previous.end)
@@ -16027,8 +16601,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
parser_lex(parser);
expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- pm_node_t *child = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
- pm_constant_path_node_t *node = pm_constant_path_node_create(parser, NULL, &delimiter, child);
+ 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);
}
@@ -16079,7 +16652,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
pm_token_t opening = parser->current;
parser_lex(parser);
- pm_node_t *body = parse_pattern(parser, captures, false, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN);
+ pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN);
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);
@@ -16138,7 +16711,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
* Parse a pattern matching expression.
*/
static pm_node_t *
-parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, bool top_pattern, pm_diagnostic_id_t diag_id) {
+parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flags, pm_diagnostic_id_t diag_id) {
pm_node_t *node = NULL;
bool leading_rest = false;
@@ -16148,14 +16721,26 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, bool top_pat
case PM_TOKEN_LABEL: {
parser_lex(parser);
pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
- return (pm_node_t *) parse_pattern_hash(parser, captures, key);
+ node = (pm_node_t *) parse_pattern_hash(parser, captures, key);
+
+ if (!(flags & PM_PARSE_PATTERN_TOP)) {
+ pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
+ }
+
+ return node;
}
case PM_TOKEN_USTAR_STAR: {
node = parse_pattern_keyword_rest(parser, captures);
- return (pm_node_t *) parse_pattern_hash(parser, captures, node);
+ node = (pm_node_t *) parse_pattern_hash(parser, captures, node);
+
+ if (!(flags & PM_PARSE_PATTERN_TOP)) {
+ pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
+ }
+
+ return node;
}
case PM_TOKEN_USTAR: {
- if (top_pattern) {
+ if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
parser_lex(parser);
node = (pm_node_t *) parse_pattern_rest(parser, captures);
leading_rest = true;
@@ -16174,7 +16759,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, bool top_pat
return (pm_node_t *) parse_pattern_hash(parser, captures, node);
}
- if (top_pattern && match1(parser, PM_TOKEN_COMMA)) {
+ if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
// If we have a comma, then we are now parsing either an array pattern or a
// find pattern. We need to parse all of the patterns, put them into a big
// list, and then determine which type of node we have.
@@ -16316,6 +16901,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
// start with a single string content node.
pm_string_t unescaped;
pm_token_t content;
+
if (match1(parser, PM_TOKEN_EOF)) {
unescaped = PM_STRING_EMPTY;
content = not_provided(parser);
@@ -16354,7 +16940,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
pm_node_list_free(&parts);
} else if (accept1(parser, PM_TOKEN_LABEL_END) && !state_is_arg_labeled) {
- node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &unescaped));
+ node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, true));
} 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);
@@ -16378,9 +16964,21 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped);
pm_node_flag_set(node, parse_unescaped_encoding(parser));
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
+
+ // Kind of odd behavior, but basically if we have an
+ // unterminated string and it ends in a newline, we back up one
+ // character so that the error message is on the last line of
+ // content in the string.
+ 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);
+
+ parser->previous.start = parser->previous.end;
+ parser->previous.type = PM_TOKEN_MISSING;
+ }
} 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, &unescaped));
+ node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, true));
} else {
// If we get here, then we have interpolation so we'll need
// to create a string or symbol node with interpolation.
@@ -16462,11 +17060,11 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
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(parser, container, current);
+ pm_interpolated_string_node_append(container, current);
current = (pm_node_t *) container;
}
- pm_interpolated_string_node_append(parser, (pm_interpolated_string_node_t *) current, node);
+ pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, node);
}
}
@@ -16485,6 +17083,11 @@ pm_parser_err_prefix(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, diag_id, pm_token_type_human(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));
+ 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]);
@@ -16711,13 +17314,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
element = (pm_node_t *) pm_keyword_hash_node_create(parser);
- pm_static_literals_t literals = { 0 };
+ 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)) {
- parse_assocs(parser, &literals, element);
+ parse_assocs(parser, &hash_keys, element);
}
- pm_static_literals_free(&literals);
+ pm_static_literals_free(&hash_keys);
parsed_bare_hash = true;
} else {
element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_ARRAY_EXPRESSION);
@@ -16728,8 +17331,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
- pm_static_literals_t literals = { 0 };
- pm_hash_key_static_literals_add(parser, &literals, element);
+ pm_static_literals_t hash_keys = { 0 };
+ pm_hash_key_static_literals_add(parser, &hash_keys, element);
pm_token_t operator;
if (parser->previous.type == PM_TOKEN_EQUAL_GREATER) {
@@ -16744,10 +17347,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
element = (pm_node_t *) hash;
if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- parse_assocs(parser, &literals, element);
+ parse_assocs(parser, &hash_keys, element);
}
- pm_static_literals_free(&literals);
+ pm_static_literals_free(&hash_keys);
parsed_bare_hash = true;
}
}
@@ -16841,7 +17444,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
return (pm_node_t *) multi_target;
}
- return parse_target_validate(parser, (pm_node_t *) multi_target);
+ return parse_target_validate(parser, (pm_node_t *) multi_target, false);
}
// If we have a single statement and are ending on a right parenthesis
@@ -16862,7 +17465,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// If we didn't find a terminator and we didn't find a right
// parenthesis, then this is a syntax error.
- if (!terminator_found) {
+ 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));
}
@@ -16891,7 +17494,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) break;
} else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
break;
- } else {
+ } 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));
}
}
@@ -16907,14 +17512,30 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous);
}
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
+ // of hash keys with this inner hash we're about to parse for the
+ // sake of warnings. We'll set it to NULL after we grab it to make
+ // sure subsequent expressions don't use it. Effectively this is a
+ // way of getting around passing it to every call to
+ // parse_expression.
+ pm_static_literals_t *current_hash_keys = parser->current_hash_keys;
+ parser->current_hash_keys = NULL;
+
pm_accepts_block_stack_push(parser, true);
parser_lex(parser);
pm_hash_node_t *node = pm_hash_node_create(parser, &parser->previous);
- pm_static_literals_t literals = { 0 };
if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
- parse_assocs(parser, &literals, (pm_node_t *) node);
+ if (current_hash_keys != NULL) {
+ parse_assocs(parser, current_hash_keys, (pm_node_t *) node);
+ } else {
+ pm_static_literals_t hash_keys = { 0 };
+ parse_assocs(parser, &hash_keys, (pm_node_t *) node);
+ pm_static_literals_free(&hash_keys);
+ }
+
accept1(parser, PM_TOKEN_NEWLINE);
}
@@ -16922,7 +17543,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM);
pm_hash_node_closing_loc_set(node, &parser->previous);
- pm_static_literals_free(&literals);
return (pm_node_t *) node;
}
case PM_TOKEN_CHARACTER_LITERAL: {
@@ -16987,12 +17607,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
case PM_TOKEN_UCOLON_COLON: {
parser_lex(parser);
-
pm_token_t delimiter = parser->previous;
- expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- pm_node_t *constant = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
- pm_node_t *node = (pm_node_t *)pm_constant_path_node_create(parser, NULL, &delimiter, constant);
+ 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);
if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX);
@@ -17152,8 +17770,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
// If we get here, then we have an empty heredoc. We'll create
// an empty content token and return an empty string node.
- lex_mode_pop(parser);
- expect1(parser, PM_TOKEN_HEREDOC_END, PM_ERR_HEREDOC_TERM);
+ expect1_heredoc_term(parser, lex_mode);
pm_token_t content = parse_strings_empty_content(parser->previous.start);
if (quote == PM_HEREDOC_QUOTE_BACKTICK) {
@@ -17194,8 +17811,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
node = (pm_node_t *) cast;
- lex_mode_pop(parser);
- expect1(parser, PM_TOKEN_HEREDOC_END, PM_ERR_HEREDOC_TERM);
+ expect1_heredoc_term(parser, lex_mode);
} 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
@@ -17217,20 +17833,18 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_interpolated_x_string_node_t *cast = pm_interpolated_xstring_node_create(parser, &opening, &opening);
cast->parts = parts;
- lex_mode_pop(parser);
- expect1(parser, PM_TOKEN_HEREDOC_END, PM_ERR_HEREDOC_TERM);
-
+ expect1_heredoc_term(parser, lex_mode);
pm_interpolated_xstring_node_closing_set(cast, &parser->previous);
+
cast->base.location = cast->opening_loc;
node = (pm_node_t *) cast;
} else {
pm_interpolated_string_node_t *cast = pm_interpolated_string_node_create(parser, &opening, &parts, &opening);
pm_node_list_free(&parts);
- lex_mode_pop(parser);
- expect1(parser, PM_TOKEN_HEREDOC_END, PM_ERR_HEREDOC_TERM);
-
+ expect1_heredoc_term(parser, lex_mode);
pm_interpolated_string_node_closing_set(cast, &parser->previous);
+
cast->base.location = cast->opening_loc;
node = (pm_node_t *) cast;
}
@@ -17451,7 +18065,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_token_t in_keyword = parser->previous;
pm_constant_id_list_t captures = { 0 };
- pm_node_t *pattern = parse_pattern(parser, &captures, true, PM_ERR_PATTERN_EXPRESSION_AFTER_IN);
+ pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN);
parser->pattern_matching_newlines = previous_pattern_matching_newlines;
pm_constant_id_list_free(&captures);
@@ -17480,7 +18094,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
then_keyword = not_provided(parser);
}
} else {
- expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
+ expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
then_keyword = parser->previous;
}
@@ -17934,7 +18548,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
lex_state_set(parser, PM_LEX_STATE_BEG);
parser->command_start = true;
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_DEF_PARAMS_TERM_PAREN);
+ 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;
}
@@ -18132,7 +18751,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
if (match1(parser, PM_TOKEN_COMMA)) {
index = parse_targets(parser, index, PM_BINDING_POWER_INDEX);
} else {
- index = parse_target(parser, index);
+ index = parse_target(parser, index, false);
}
context_pop(parser);
@@ -18254,9 +18873,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_token_t double_colon = parser->previous;
expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- pm_node_t *constant = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
-
- constant_path = (pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, constant);
+ 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,
@@ -18636,15 +19253,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// 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);
+ 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(parser, interpolated, current);
- pm_interpolated_string_node_append(parser, interpolated, string);
+ pm_interpolated_string_node_append(interpolated, current);
+ pm_interpolated_string_node_append(interpolated, string);
current = (pm_node_t *) interpolated;
} else {
assert(false && "unreachable");
@@ -18669,7 +19286,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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(parser, interpolated, current);
+ pm_interpolated_string_node_append(interpolated, current);
current = (pm_node_t *) interpolated;
} else {
// If we hit an embedded variable and the current
@@ -18678,7 +19295,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
pm_node_t *part = parse_string_part(parser);
- pm_interpolated_string_node_append(parser, (pm_interpolated_string_node_t *) current, part);
+ pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part);
break;
}
case PM_TOKEN_EMBEXPR_BEGIN: {
@@ -18698,7 +19315,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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(parser, interpolated, current);
+ 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
@@ -18709,7 +19326,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
pm_node_t *part = parse_string_part(parser);
- pm_interpolated_string_node_append(parser, (pm_interpolated_string_node_t *) current, part);
+ pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part);
break;
}
default:
@@ -18785,6 +19402,14 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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);
+
+ 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
+ // are in a US-ASCII file, no matter its contents.
+ pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
+ }
+
pm_interpolated_regular_expression_node_append(interpolated, part);
} else {
// If the first part of the body of the regular expression is not a
@@ -18913,7 +19538,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
if (match1(parser, PM_TOKEN_COMMA)) {
return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX);
} else {
- return parse_target_validate(parser, splat);
+ return parse_target_validate(parser, splat, true);
}
}
case PM_TOKEN_BANG: {
@@ -19259,39 +19884,6 @@ parse_call_operator_write(pm_parser_t *parser, pm_call_node_t *call_node, const
}
/**
- * Returns true if the name of the capture group is a valid local variable that
- * can be written to.
- */
-static bool
-parse_regular_expression_named_capture(pm_parser_t *parser, const uint8_t *source, size_t length) {
- if (length == 0) {
- return false;
- }
-
- // First ensure that it starts with a valid identifier starting character.
- size_t width = char_is_identifier_start(parser, source);
- if (!width) {
- return false;
- }
-
- // Next, ensure that it's not an uppercase character.
- if (parser->encoding_changed) {
- if (parser->encoding->isupper_char(source, (ptrdiff_t) length)) return false;
- } else {
- if (pm_encoding_utf_8_isupper_char(source, (ptrdiff_t) length)) return false;
- }
-
- // Next, iterate through all of the bytes of the string to ensure that they
- // are all valid identifier characters.
- const uint8_t *cursor = source + width;
- while (cursor < source + length && (width = char_is_identifier(parser, cursor))) {
- cursor += width;
- }
-
- return cursor == source + length;
-}
-
-/**
* Potentially change a =~ with a regular expression with named captures into a
* match write node.
*/
@@ -19317,7 +19909,7 @@ parse_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t *
// If the name of the capture group isn't a valid identifier, we do
// not add it to the local table.
- if (!parse_regular_expression_named_capture(parser, source, length)) continue;
+ if (!pm_slice_is_valid_local(parser, source, source + length)) continue;
if (content->type == PM_STRING_SHARED) {
// If the unescaped string is a slice of the source, then we can
@@ -19775,7 +20367,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_previous(parser, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_type_human(parser->current.type));
return node;
}
}
@@ -20046,8 +20638,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
path = (pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
} else {
// Otherwise, this is a constant path. That would look like Foo::Bar.
- pm_node_t *child = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
- path = (pm_node_t *)pm_constant_path_node_create(parser, node, &delimiter, child);
+ path = (pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->previous);
}
// If this is followed by a comma then it is a multiple assignment.
@@ -20086,9 +20677,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
}
default: {
- pm_parser_err_token(parser, &delimiter, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- pm_node_t *child = (pm_node_t *) pm_missing_node_create(parser, delimiter.start, delimiter.end);
- return (pm_node_t *)pm_constant_path_node_create(parser, node, &delimiter, child);
+ 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);
}
}
}
@@ -20159,7 +20749,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
parser_lex(parser);
pm_constant_id_list_t captures = { 0 };
- pm_node_t *pattern = parse_pattern(parser, &captures, true, PM_ERR_PATTERN_EXPRESSION_AFTER_IN);
+ pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN);
parser->pattern_matching_newlines = previous_pattern_matching_newlines;
pm_constant_id_list_free(&captures);
@@ -20176,7 +20766,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
parser_lex(parser);
pm_constant_id_list_t captures = { 0 };
- pm_node_t *pattern = parse_pattern(parser, &captures, true, PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET);
+ pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET);
parser->pattern_matching_newlines = previous_pattern_matching_newlines;
pm_constant_id_list_free(&captures);
@@ -20189,6 +20779,10 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
}
}
+#undef PM_PARSE_PATTERN_SINGLE
+#undef PM_PARSE_PATTERN_TOP
+#undef PM_PARSE_PATTERN_MULTI
+
/**
* Parse an expression at the given point of the parser using the given binding
* power to parse subsequent chains. If this function finds a syntax error, it
@@ -20997,6 +21591,7 @@ typedef struct {
#define PM_COLOR_GRAY "\033[38;5;102m"
#define PM_COLOR_RED "\033[1;31m"
#define PM_COLOR_RESET "\033[m"
+#define PM_ERROR_TRUNCATE 30
static inline pm_error_t *
pm_parser_errors_format_sort(const pm_parser_t *parser, const pm_list_t *error_list, const pm_newline_list_t *newline_list) {
@@ -21051,7 +21646,7 @@ pm_parser_errors_format_sort(const pm_parser_t *parser, const pm_list_t *error_l
}
static inline void
-pm_parser_errors_format_line(const pm_parser_t *parser, const pm_newline_list_t *newline_list, const char *number_prefix, int32_t line, pm_buffer_t *buffer) {
+pm_parser_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;
assert(line_delta >= 0);
@@ -21068,9 +21663,25 @@ pm_parser_errors_format_line(const pm_parser_t *parser, const pm_newline_list_t
}
pm_buffer_append_format(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;
+ 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);
+ start += column_start;
+ }
+
pm_buffer_append_string(buffer, (const char *) start, (size_t) (end - start));
- if (end == parser->end && end[-1] != '\n') {
+ 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);
}
}
@@ -21185,6 +21796,7 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
// display the same line twice in case the errors are close enough in the
// source.
int32_t last_line = parser->start_line - 1;
+ uint32_t last_column_start = 0;
const pm_encoding_t *encoding = parser->encoding;
for (size_t index = 0; index < error_list->size; index++) {
@@ -21199,11 +21811,11 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
}
pm_buffer_append_string(buffer, " ", 2);
- pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, error->line - 2, buffer);
+ pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, error->line - 2, 0, 0, buffer);
}
pm_buffer_append_string(buffer, " ", 2);
- pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, error->line - 1, buffer);
+ pm_parser_errors_format_line(parser, newline_list, 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
@@ -21214,7 +21826,17 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
} else {
pm_buffer_append_string(buffer, "> ", 2);
}
- pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, error->line, 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++) {
+ if (errors[next_index].line != error->line) break;
+ if (errors[next_index].column_end > column_end) column_end = errors[next_index].column_end;
+ }
+
+ pm_parser_errors_format_line(parser, newline_list, 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]];
@@ -21233,25 +21855,33 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
pm_buffer_append_string(buffer, error_format.blank_prefix, error_format.blank_prefix_length);
size_t column = 0;
- while (column < error->column_end) {
- if (column < error->column_start) {
- pm_buffer_append_byte(buffer, ' ');
- } else {
- const uint8_t caret = column == error->column_start ? '^' : '~';
+ if (last_column_start >= PM_ERROR_TRUNCATE) {
+ pm_buffer_append_string(buffer, " ", 4);
+ column = last_column_start;
+ }
- if (colorize) {
- pm_buffer_append_string(buffer, PM_COLOR_RED, 7);
- pm_buffer_append_byte(buffer, caret);
- pm_buffer_append_string(buffer, PM_COLOR_RESET, 3);
- } else {
- pm_buffer_append_byte(buffer, caret);
- }
- }
+ while (column < error->column_start) {
+ pm_buffer_append_byte(buffer, ' ');
size_t char_width = encoding->char_width(start + column, parser->end - (start + column));
column += (char_width == 0 ? 1 : char_width);
}
+ if (colorize) pm_buffer_append_string(buffer, PM_COLOR_RED, 7);
+ pm_buffer_append_byte(buffer, '^');
+
+ size_t char_width = encoding->char_width(start + column, parser->end - (start + column));
+ column += (char_width == 0 ? 1 : char_width);
+
+ while (column < error->column_end) {
+ pm_buffer_append_byte(buffer, '~');
+
+ size_t char_width = encoding->char_width(start + column, parser->end - (start + column));
+ column += (char_width == 0 ? 1 : char_width);
+ }
+
+ if (colorize) pm_buffer_append_string(buffer, PM_COLOR_RESET, 3);
+
if (inline_messages) {
pm_buffer_append_byte(buffer, ' ');
assert(error->error != NULL);
@@ -21269,12 +21899,12 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
if (next_line - last_line > 1) {
pm_buffer_append_string(buffer, " ", 2);
- pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, ++last_line, buffer);
+ pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, ++last_line, 0, 0, buffer);
}
if (next_line - last_line > 1) {
pm_buffer_append_string(buffer, " ", 2);
- pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, ++last_line, buffer);
+ pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, ++last_line, 0, 0, buffer);
}
}
@@ -21282,6 +21912,7 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
xfree(errors);
}
+#undef PM_ERROR_TRUNCATE
#undef PM_COLOR_GRAY
#undef PM_COLOR_RED
#undef PM_COLOR_RESET
diff --git a/prism/static_literals.c b/prism/static_literals.c
index 469bdfd5ea..08f61c81fa 100644
--- a/prism/static_literals.c
+++ b/prism/static_literals.c
@@ -1,5 +1,21 @@
#include "prism/static_literals.h"
+/**
+ * A small struct used for passing around a subset of the information that is
+ * stored on the parser. We use this to avoid having static literals explicitly
+ * depend on the parser struct.
+ */
+typedef struct {
+ /** The list of newline offsets to use to calculate line numbers. */
+ const pm_newline_list_t *newline_list;
+
+ /** The line number that the parser starts on. */
+ int32_t start_line;
+
+ /** The name of the encoding that the parser is using. */
+ const char *encoding_name;
+} pm_static_literals_metadata_t;
+
static inline uint32_t
murmur_scramble(uint32_t value) {
value *= 0xcc9e2d51;
@@ -48,7 +64,7 @@ murmur_hash(const uint8_t *key, size_t length) {
* these hashes to look for duplicates.
*/
static uint32_t
-node_hash(const pm_parser_t *parser, const pm_node_t *node) {
+node_hash(const pm_static_literals_metadata_t *metadata, const pm_node_t *node) {
switch (PM_NODE_TYPE(node)) {
case PM_INTEGER_NODE: {
// Integers hash their value.
@@ -68,7 +84,7 @@ node_hash(const pm_parser_t *parser, 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(&parser->newline_list, node->location.start, parser->start_line);
+ const pm_line_column_t line_column = pm_newline_list_line_column(metadata->newline_list, node->location.start, metadata->start_line);
const int32_t *value = &line_column.line;
return murmur_hash((const uint8_t *) value, sizeof(int32_t));
}
@@ -82,14 +98,14 @@ node_hash(const pm_parser_t *parser, const pm_node_t *node) {
// is stored as a subnode, we hash that node and then mix in the
// fact that this is a rational node.
const pm_node_t *numeric = ((const pm_rational_node_t *) node)->numeric;
- return node_hash(parser, numeric) ^ murmur_scramble((uint32_t) node->type);
+ return node_hash(metadata, numeric) ^ murmur_scramble((uint32_t) node->type);
}
case PM_IMAGINARY_NODE: {
// Imaginaries hash their numeric value. Because their numeric value
// is stored as a subnode, we hash that node and then mix in the
// fact that this is an imaginary node.
const pm_node_t *numeric = ((const pm_imaginary_node_t *) node)->numeric;
- return node_hash(parser, numeric) ^ murmur_scramble((uint32_t) node->type);
+ return node_hash(metadata, numeric) ^ murmur_scramble((uint32_t) node->type);
}
case PM_STRING_NODE: {
// Strings hash their value and mix in their flags so that different
@@ -132,7 +148,7 @@ node_hash(const pm_parser_t *parser, const pm_node_t *node) {
* and must be able to compare all node types that will be stored in this hash.
*/
static pm_node_t *
-pm_node_hash_insert(pm_node_hash_t *hash, const pm_parser_t *parser, pm_node_t *node, int (*compare)(const pm_parser_t *parser, const pm_node_t *left, const pm_node_t *right)) {
+pm_node_hash_insert(pm_node_hash_t *hash, const pm_static_literals_metadata_t *metadata, pm_node_t *node, int (*compare)(const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right)) {
// If we are out of space, we need to resize the hash. This will cause all
// of the nodes to be rehashed and reinserted into the new hash.
if (hash->size * 2 >= hash->capacity) {
@@ -152,7 +168,7 @@ pm_node_hash_insert(pm_node_hash_t *hash, const pm_parser_t *parser, pm_node_t *
pm_node_t *node = hash->nodes[index];
if (node != NULL) {
- uint32_t index = node_hash(parser, node) & mask;
+ uint32_t index = node_hash(metadata, node) & mask;
new_nodes[index] = node;
}
}
@@ -165,14 +181,14 @@ pm_node_hash_insert(pm_node_hash_t *hash, const pm_parser_t *parser, pm_node_t *
// Now, insert the node into the hash.
uint32_t mask = hash->capacity - 1;
- uint32_t index = node_hash(parser, node) & mask;
+ uint32_t index = node_hash(metadata, node) & mask;
// We use linear probing to resolve collisions. This means that if the
// current index is occupied, we will move to the next index and try again.
// We are guaranteed that this will eventually find an empty slot because we
// resize the hash when it gets too full.
while (hash->nodes[index] != NULL) {
- if (compare(parser, hash->nodes[index], node) == 0) break;
+ if (compare(metadata, hash->nodes[index], node) == 0) break;
index = (index + 1) & mask;
}
@@ -203,7 +219,7 @@ pm_node_hash_free(pm_node_hash_t *hash) {
* Return the integer value of the given node as an int64_t.
*/
static int64_t
-pm_int64_value(const pm_parser_t *parser, const pm_node_t *node) {
+pm_int64_value(const pm_static_literals_metadata_t *metadata, const pm_node_t *node) {
switch (PM_NODE_TYPE(node)) {
case PM_INTEGER_NODE: {
const pm_integer_t *integer = &((const pm_integer_node_t *) node)->value;
@@ -213,7 +229,7 @@ pm_int64_value(const pm_parser_t *parser, const pm_node_t *node) {
return integer->negative ? -value : value;
}
case PM_SOURCE_LINE_NODE:
- return (int64_t) pm_newline_list_line_column(&parser->newline_list, node->location.start, parser->start_line).line;
+ return (int64_t) pm_newline_list_line_column(metadata->newline_list, node->location.start, metadata->start_line).line;
default:
assert(false && "unreachable");
return 0;
@@ -225,10 +241,10 @@ pm_int64_value(const pm_parser_t *parser, const pm_node_t *node) {
* instances.
*/
static int
-pm_compare_integer_nodes(const pm_parser_t *parser, const pm_node_t *left, const pm_node_t *right) {
+pm_compare_integer_nodes(const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
if (PM_NODE_TYPE_P(left, PM_SOURCE_LINE_NODE) || PM_NODE_TYPE_P(right, PM_SOURCE_LINE_NODE)) {
- int64_t left_value = pm_int64_value(parser, left);
- int64_t right_value = pm_int64_value(parser, right);
+ int64_t left_value = pm_int64_value(metadata, left);
+ int64_t right_value = pm_int64_value(metadata, right);
return PM_NUMERIC_COMPARISON(left_value, right_value);
}
@@ -241,7 +257,7 @@ pm_compare_integer_nodes(const pm_parser_t *parser, const pm_node_t *left, const
* A comparison function for comparing two FloatNode instances.
*/
static int
-pm_compare_float_nodes(PRISM_ATTRIBUTE_UNUSED const pm_parser_t *parser, const pm_node_t *left, const pm_node_t *right) {
+pm_compare_float_nodes(PRISM_ATTRIBUTE_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);
@@ -251,20 +267,20 @@ pm_compare_float_nodes(PRISM_ATTRIBUTE_UNUSED const pm_parser_t *parser, const p
* A comparison function for comparing two nodes that have attached numbers.
*/
static int
-pm_compare_number_nodes(const pm_parser_t *parser, const pm_node_t *left, const pm_node_t *right) {
+pm_compare_number_nodes(const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
if (PM_NODE_TYPE(left) != PM_NODE_TYPE(right)) {
return PM_NUMERIC_COMPARISON(PM_NODE_TYPE(left), PM_NODE_TYPE(right));
}
switch (PM_NODE_TYPE(left)) {
case PM_IMAGINARY_NODE:
- return pm_compare_number_nodes(parser, ((const pm_imaginary_node_t *) left)->numeric, ((const pm_imaginary_node_t *) right)->numeric);
+ return pm_compare_number_nodes(metadata, ((const pm_imaginary_node_t *) left)->numeric, ((const pm_imaginary_node_t *) right)->numeric);
case PM_RATIONAL_NODE:
- return pm_compare_number_nodes(parser, ((const pm_rational_node_t *) left)->numeric, ((const pm_rational_node_t *) right)->numeric);
+ return pm_compare_number_nodes(metadata, ((const pm_rational_node_t *) left)->numeric, ((const pm_rational_node_t *) right)->numeric);
case PM_INTEGER_NODE:
- return pm_compare_integer_nodes(parser, left, right);
+ return pm_compare_integer_nodes(metadata, left, right);
case PM_FLOAT_NODE:
- return pm_compare_float_nodes(parser, left, right);
+ return pm_compare_float_nodes(metadata, left, right);
default:
assert(false && "unreachable");
return 0;
@@ -293,7 +309,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_parser_t *parser, const pm_node_t *left, const pm_node_t *right) {
+pm_compare_string_nodes(PRISM_ATTRIBUTE_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);
@@ -303,7 +319,7 @@ pm_compare_string_nodes(PRISM_ATTRIBUTE_UNUSED const pm_parser_t *parser, const
* A comparison function for comparing two RegularExpressionNode instances.
*/
static int
-pm_compare_regular_expression_nodes(PRISM_ATTRIBUTE_UNUSED const pm_parser_t *parser, const pm_node_t *left, const pm_node_t *right) {
+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) {
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;
@@ -319,23 +335,77 @@ pm_compare_regular_expression_nodes(PRISM_ATTRIBUTE_UNUSED const pm_parser_t *pa
* Add a node to the set of static literals.
*/
pm_node_t *
-pm_static_literals_add(const pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node) {
+pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line, pm_static_literals_t *literals, pm_node_t *node) {
switch (PM_NODE_TYPE(node)) {
case PM_INTEGER_NODE:
case PM_SOURCE_LINE_NODE:
- return pm_node_hash_insert(&literals->integer_nodes, parser, node, pm_compare_integer_nodes);
+ return pm_node_hash_insert(
+ &literals->integer_nodes,
+ &(pm_static_literals_metadata_t) {
+ .newline_list = newline_list,
+ .start_line = start_line,
+ .encoding_name = NULL
+ },
+ node,
+ pm_compare_integer_nodes
+ );
case PM_FLOAT_NODE:
- return pm_node_hash_insert(&literals->float_nodes, parser, node, pm_compare_float_nodes);
+ return pm_node_hash_insert(
+ &literals->float_nodes,
+ &(pm_static_literals_metadata_t) {
+ .newline_list = newline_list,
+ .start_line = start_line,
+ .encoding_name = NULL
+ },
+ node,
+ pm_compare_float_nodes
+ );
case PM_RATIONAL_NODE:
case PM_IMAGINARY_NODE:
- return pm_node_hash_insert(&literals->number_nodes, parser, node, pm_compare_number_nodes);
+ return pm_node_hash_insert(
+ &literals->number_nodes,
+ &(pm_static_literals_metadata_t) {
+ .newline_list = newline_list,
+ .start_line = start_line,
+ .encoding_name = NULL
+ },
+ node,
+ pm_compare_number_nodes
+ );
case PM_STRING_NODE:
case PM_SOURCE_FILE_NODE:
- return pm_node_hash_insert(&literals->string_nodes, parser, node, pm_compare_string_nodes);
+ return pm_node_hash_insert(
+ &literals->string_nodes,
+ &(pm_static_literals_metadata_t) {
+ .newline_list = newline_list,
+ .start_line = start_line,
+ .encoding_name = NULL
+ },
+ node,
+ pm_compare_string_nodes
+ );
case PM_REGULAR_EXPRESSION_NODE:
- return pm_node_hash_insert(&literals->regexp_nodes, parser, node, pm_compare_regular_expression_nodes);
+ return pm_node_hash_insert(
+ &literals->regexp_nodes,
+ &(pm_static_literals_metadata_t) {
+ .newline_list = newline_list,
+ .start_line = start_line,
+ .encoding_name = NULL
+ },
+ node,
+ pm_compare_regular_expression_nodes
+ );
case PM_SYMBOL_NODE:
- return pm_node_hash_insert(&literals->symbol_nodes, parser, node, pm_compare_string_nodes);
+ return pm_node_hash_insert(
+ &literals->symbol_nodes,
+ &(pm_static_literals_metadata_t) {
+ .newline_list = newline_list,
+ .start_line = start_line,
+ .encoding_name = NULL
+ },
+ node,
+ pm_compare_string_nodes
+ );
case PM_TRUE_NODE: {
pm_node_t *duplicated = literals->true_node;
literals->true_node = node;
@@ -435,8 +505,8 @@ pm_rational_inspect(pm_buffer_t *buffer, pm_rational_node_t *node) {
/**
* Create a string-based representation of the given static literal.
*/
-PRISM_EXPORTED_FUNCTION void
-pm_static_literal_inspect(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node) {
+static 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:
pm_buffer_append_string(buffer, "false", 5);
@@ -473,7 +543,7 @@ pm_static_literal_inspect(pm_buffer_t *buffer, const pm_parser_t *parser, const
const pm_node_t *numeric = ((const pm_imaginary_node_t *) node)->numeric;
pm_buffer_append_string(buffer, "(0", 2);
if (pm_static_literal_positive_p(numeric)) pm_buffer_append_byte(buffer, '+');
- pm_static_literal_inspect(buffer, parser, numeric);
+ pm_static_literal_inspect_node(buffer, metadata, numeric);
if (PM_NODE_TYPE_P(numeric, PM_RATIONAL_NODE)) pm_buffer_append_byte(buffer, '*');
pm_buffer_append_string(buffer, "i)", 2);
break;
@@ -490,7 +560,7 @@ pm_static_literal_inspect(pm_buffer_t *buffer, const pm_parser_t *parser, const
switch (PM_NODE_TYPE(numeric)) {
case PM_INTEGER_NODE:
pm_buffer_append_byte(buffer, '(');
- pm_static_literal_inspect(buffer, parser, numeric);
+ pm_static_literal_inspect_node(buffer, metadata, numeric);
pm_buffer_append_string(buffer, "/1)", 3);
break;
case PM_FLOAT_NODE:
@@ -517,7 +587,7 @@ pm_static_literal_inspect(pm_buffer_t *buffer, const pm_parser_t *parser, const
break;
}
case PM_SOURCE_ENCODING_NODE:
- pm_buffer_append_format(buffer, "#<Encoding:%s>", parser->encoding->name);
+ pm_buffer_append_format(buffer, "#<Encoding:%s>", metadata->encoding_name);
break;
case PM_SOURCE_FILE_NODE: {
const pm_string_t *filepath = &((const pm_source_file_node_t *) node)->filepath;
@@ -527,7 +597,7 @@ pm_static_literal_inspect(pm_buffer_t *buffer, const pm_parser_t *parser, const
break;
}
case PM_SOURCE_LINE_NODE:
- pm_buffer_append_format(buffer, "%d", pm_newline_list_line_column(&parser->newline_list, node->location.start, parser->start_line).line);
+ pm_buffer_append_format(buffer, "%d", pm_newline_list_line_column(metadata->newline_list, node->location.start, metadata->start_line).line);
break;
case PM_STRING_NODE: {
const pm_string_t *unescaped = &((const pm_string_node_t *) node)->unescaped;
@@ -550,3 +620,19 @@ pm_static_literal_inspect(pm_buffer_t *buffer, const pm_parser_t *parser, const
break;
}
}
+
+/**
+ * Create a string-based representation of the given static literal.
+ */
+PRISM_EXPORTED_FUNCTION 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_node(
+ buffer,
+ &(pm_static_literals_metadata_t) {
+ .newline_list = newline_list,
+ .start_line = start_line,
+ .encoding_name = encoding_name
+ },
+ node
+ );
+}
diff --git a/prism/static_literals.h b/prism/static_literals.h
index dd1f2e7f84..72706054c1 100644
--- a/prism/static_literals.h
+++ b/prism/static_literals.h
@@ -8,8 +8,7 @@
#include "prism/defines.h"
#include "prism/ast.h"
-#include "prism/node.h"
-#include "prism/parser.h"
+#include "prism/util/pm_newline_list.h"
#include <assert.h>
#include <stdbool.h>
@@ -92,12 +91,13 @@ typedef struct {
/**
* Add a node to the set of static literals.
*
- * @param parser The parser that created the node.
+ * @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.
* @return A pointer to the node that is being overwritten, if there is one.
*/
-pm_node_t * pm_static_literals_add(const pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node);
+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);
/**
* Free the internal memory associated with the given static literals set.
@@ -110,9 +110,11 @@ 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 parser The parser that created the node.
+ * @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.
*/
-PRISM_EXPORTED_FUNCTION void pm_static_literal_inspect(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node);
+PRISM_EXPORTED_FUNCTION 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/templates/ext/prism/api_node.c.erb b/prism/templates/ext/prism/api_node.c.erb
index 0e8aaae322..0e3e4d63cc 100644
--- a/prism/templates/ext/prism/api_node.c.erb
+++ b/prism/templates/ext/prism/api_node.c.erb
@@ -76,8 +76,7 @@ pm_source_new(const pm_parser_t *parser, rb_encoding *encoding) {
rb_ary_push(offsets, ULONG2NUM(parser->newline_list.offsets[index]));
}
- VALUE source_argv[] = { source_string, LONG2NUM(parser->start_line), offsets };
- return rb_class_new_instance(3, source_argv, rb_cPrismSource);
+ return rb_funcall(rb_cPrismSource, rb_intern("for"), 3, source_string, LONG2NUM(parser->start_line), offsets);
}
typedef struct pm_node_stack_node {
@@ -108,21 +107,21 @@ pm_node_stack_pop(pm_node_stack_node_t **stack) {
VALUE
pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encoding, VALUE source) {
- ID *constants = xcalloc(parser->constant_pool.size, sizeof(ID));
+ 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;
VALUE string = rb_enc_str_new((const char *) constant->start, constant->length, encoding);
- ID value = rb_protect(rb_intern_str, string, &state);
+ VALUE value = rb_protect(rb_str_intern, string, &state);
if (state != 0) {
- value = rb_intern_const("?");
+ value = ID2SYM(rb_intern_const("?"));
rb_set_errinfo(Qnil);
}
- constants[index] = value;
+ rb_ary_push(constants, value);
}
pm_node_stack_node_t *node_stack = NULL;
@@ -197,15 +196,15 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
<%- when Prism::Template::ConstantField -%>
#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
assert(cast-><%= field.name %> != 0);
- argv[<%= index %>] = rb_id2sym(constants[cast-><%= field.name %> - 1]);
+ argv[<%= index %>] = RARRAY_AREF(constants, cast-><%= field.name %> - 1);
<%- when Prism::Template::OptionalConstantField -%>
- argv[<%= index %>] = cast-><%= field.name %> == 0 ? Qnil : rb_id2sym(constants[cast-><%= field.name %> - 1]);
+ argv[<%= index %>] = cast-><%= field.name %> == 0 ? Qnil : RARRAY_AREF(constants, cast-><%= field.name %> - 1);
<%- when Prism::Template::ConstantListField -%>
#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
argv[<%= index %>] = rb_ary_new_capa(cast-><%= field.name %>.size);
for (size_t index = 0; index < cast-><%= field.name %>.size; index++) {
assert(cast-><%= field.name %>.ids[index] != 0);
- rb_ary_push(argv[<%= index %>], rb_id2sym(constants[cast-><%= field.name %>.ids[index] - 1]));
+ rb_ary_push(argv[<%= index %>], RARRAY_AREF(constants, cast-><%= field.name %>.ids[index] - 1));
}
<%- when Prism::Template::LocationField -%>
#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
@@ -246,9 +245,7 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
}
}
- VALUE result = rb_ary_pop(value_stack);
- xfree(constants);
- return result;
+ return rb_ary_pop(value_stack);
}
void
diff --git a/prism/templates/lib/prism/dsl.rb.erb b/prism/templates/lib/prism/dsl.rb.erb
index 8dbb540952..eff0d1c4fc 100644
--- a/prism/templates/lib/prism/dsl.rb.erb
+++ b/prism/templates/lib/prism/dsl.rb.erb
@@ -2,7 +2,7 @@ module Prism
# The DSL module provides a set of methods that can be used to create prism
# nodes in a more concise manner. For example, instead of writing:
#
- # source = Prism::Source.new("[1]")
+ # source = Prism::Source.for("[1]")
#
# Prism::ArrayNode.new(
# [
@@ -20,7 +20,7 @@ module Prism
#
# you could instead write:
#
- # source = Prism::Source.new("[1]")
+ # source = Prism::Source.for("[1]")
#
# ArrayNode(
# IntegerNode(Prism::IntegerBaseFlags::DECIMAL, 1, Location(source, 1, 1)), source),
diff --git a/prism/templates/lib/prism/inspect_visitor.rb.erb b/prism/templates/lib/prism/inspect_visitor.rb.erb
new file mode 100644
index 0000000000..9328da636b
--- /dev/null
+++ b/prism/templates/lib/prism/inspect_visitor.rb.erb
@@ -0,0 +1,132 @@
+module Prism
+ # This visitor is responsible for composing the strings that get returned by
+ # the various #inspect methods defined on each of the nodes.
+ class InspectVisitor < Visitor
+ # Most of the time, we can simply pass down the indent to the next node.
+ # However, when we are inside a list we want some extra special formatting
+ # 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
+
+ def initialize(value)
+ @value = value
+ end
+ end
+
+ private_constant :Replace
+
+ # The current prefix string.
+ attr_reader :indent
+
+ # The list of commands that we need to execute in order to compose the
+ # final string.
+ attr_reader :commands
+
+ # Initializes a new instance of the InspectVisitor.
+ def initialize(indent = +"")
+ @indent = indent
+ @commands = []
+ end
+
+ # Compose an inspect string for the given node.
+ def self.compose(node)
+ visitor = new
+ node.accept(visitor)
+ visitor.compose
+ end
+
+ # Compose the final string.
+ def compose
+ buffer = +""
+ replace = nil
+
+ until commands.empty?
+ # @type var command: String | node | Replace
+ # @type var indent: String
+ command, indent = *commands.shift
+
+ case command
+ when String
+ buffer << (replace || indent)
+ buffer << command
+ replace = nil
+ when Node
+ visitor = InspectVisitor.new(indent)
+ command.accept(visitor)
+ @commands = [*visitor.commands, *@commands]
+ when Replace
+ replace = command.value
+ else
+ raise "Unknown command: #{command.inspect}"
+ end
+ end
+
+ buffer
+ end
+ <%- nodes.each do |node| -%>
+
+ # Inspect a <%= node.name %> node.
+ def visit_<%= node.human %>(node)
+ commands << [inspect_node(<%= node.name.inspect %>, node), indent]
+ <%- node.fields.each_with_index do |field, index| -%>
+ <%- pointer = index == node.fields.length - 1 ? "└── " : "├── " -%>
+ <%- preadd = index == node.fields.length - 1 ? " " : "│ " -%>
+ <%- case field -%>
+ <%- when Prism::Template::NodeListField -%>
+ commands << ["<%= pointer %><%= field.name %>: (length: #{(<%= field.name %> = node.<%= field.name %>).length})\n", indent]
+ if <%= field.name %>.any?
+ <%= field.name %>[0...-1].each do |child|
+ commands << [Replace.new("#{indent}<%= preadd %>├── "), indent]
+ commands << [child, "#{indent}<%= preadd %>│ "]
+ end
+ commands << [Replace.new("#{indent}<%= preadd %>└── "), indent]
+ commands << [<%= field.name %>[-1], "#{indent}<%= preadd %> "]
+ end
+ <%- when Prism::Template::NodeField -%>
+ commands << ["<%= pointer %><%= field.name %>:\n", indent]
+ commands << [node.<%= field.name %>, "#{indent}<%= preadd %>"]
+ <%- when Prism::Template::OptionalNodeField -%>
+ if (<%= field.name %> = node.<%= field.name %>).nil?
+ commands << ["<%= pointer %><%= field.name %>: ∅\n", indent]
+ else
+ commands << ["<%= pointer %><%= field.name %>:\n", indent]
+ commands << [<%= field.name %>, "#{indent}<%= preadd %>"]
+ end
+ <%- when Prism::Template::ConstantField, Prism::Template::ConstantListField, Prism::Template::StringField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::IntegerField, Prism::Template::DoubleField -%>
+ commands << ["<%= pointer %><%= field.name %>: #{node.<%= field.name %>.inspect}\n", indent]
+ <%- when Prism::Template::OptionalConstantField -%>
+ if (<%= field.name %> = node.<%= field.name %>).nil?
+ commands << ["<%= pointer %><%= field.name %>: ∅\n", indent]
+ else
+ commands << ["<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n", indent]
+ end
+ <%- when Prism::Template::FlagsField -%>
+ <%- flag = flags.find { |flag| flag.name == field.kind }.tap { |flag| raise unless flag } -%>
+ flags = [<%= flag.values.map { |value| "(\"#{value.name.downcase}\" if node.#{value.name.downcase}?)" }.join(", ") %>].compact
+ commands << ["<%= pointer %><%= field.name %>: #{flags.empty? ? "∅" : flags.join(", ")}\n", indent]
+ <%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField -%>
+ commands << ["<%= pointer %><%= field.name %>: #{inspect_location(node.<%= field.name %>)}\n", indent]
+ <%- end -%>
+ <%- end -%>
+ end
+ <%- end -%>
+
+ private
+
+ # Compose a header for the given node.
+ def inspect_node(name, node)
+ 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)
+ if location
+ "(#{location.start_line},#{location.start_column})-(#{location.end_line},#{location.end_column}) = #{location.slice.inspect}"
+ else
+ "∅"
+ end
+ end
+ end
+end
diff --git a/prism/templates/lib/prism/node.rb.erb b/prism/templates/lib/prism/node.rb.erb
index 6b5a285315..f0ce226def 100644
--- a/prism/templates/lib/prism/node.rb.erb
+++ b/prism/templates/lib/prism/node.rb.erb
@@ -28,23 +28,27 @@ module Prism
location.is_a?(Location) ? location.end_offset : ((location >> 32) + (location & 0xFFFFFFFF))
end
- def newline? # :nodoc:
- @newline ? true : false
+ # Returns all of the lines of the source code associated with this node.
+ def source_lines
+ location.source_lines
end
- def set_newline_flag(newline_marked) # :nodoc:
- line = location.start_line
- unless newline_marked[line]
- newline_marked[line] = true
- @newline = true
- end
- end
+ # An alias for source_lines, used to mimic the API from
+ # RubyVM::AbstractSyntaxTree to make it easier to migrate.
+ alias script_lines source_lines
# Slice the location of the node from the source.
def slice
location.slice
end
+ # 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.
+ def slice_lines
+ location.slice_lines
+ end
+
# Similar to inspect, but respects the current level of indentation given by
# the pretty print object.
def pretty_print(q)
@@ -60,6 +64,43 @@ module Prism
DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot
end
+ # Returns a list of nodes that are descendants of this node that contain the
+ # given line and column. This is useful for locating a node that is selected
+ # based on the line and column of the source code.
+ #
+ # Important to note is that the column given to this method should be in
+ # bytes, as opposed to characters or code units.
+ def tunnel(line, column)
+ queue = [self] #: Array[Prism::node]
+ result = []
+
+ 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
+ queue << child_node
+ break
+ end
+ end
+ end
+
+ result
+ end
+
# 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.
@@ -110,7 +151,7 @@ module Prism
end
# Returns a string representation of the node.
- def inspect(inspector = NodeInspector.new)
+ def inspect
raise NoMethodError, "undefined method `inspect' for #{inspect}"
end
@@ -128,7 +169,6 @@ module Prism
# def initialize: (<%= (node.fields.map { |field| "#{field.rbs_class} #{field.name}" } + ["Location location"]).join(", ") %>) -> void
def initialize(source, <%= (node.fields.map(&:name) + ["location"]).join(", ") %>)
@source = source
- @newline = false
@location = location
<%- node.fields.each do |field| -%>
<%- if Prism::Template::CHECK_FIELD_KIND && field.respond_to?(:check_field_kind) -%>
@@ -142,25 +182,6 @@ module Prism
def accept(visitor)
visitor.visit_<%= node.human %>(self)
end
- <%- if node.newline == false -%>
-
- def set_newline_flag(newline_marked) # :nodoc:
- # Never mark <%= node.name %> with a newline flag, mark children instead
- end
- <%- elsif node.newline.is_a?(String) -%>
-
- def set_newline_flag(newline_marked) # :nodoc:
- <%- field = node.fields.find { |f| f.name == node.newline } or raise node.newline -%>
- <%- case field -%>
- <%- when Prism::Template::NodeField -%>
- <%= field.name %>.set_newline_flag(newline_marked)
- <%- when Prism::Template::NodeListField -%>
- first = <%= field.name %>.first
- first.set_newline_flag(newline_marked) if first
- <%- else raise field.class.name -%>
- <%- end -%>
- end
- <%- end -%>
# def child_nodes: () -> Array[nil | Node]
def child_nodes
@@ -219,10 +240,10 @@ module Prism
def deconstruct_keys(keys)
{ <%= (node.fields.map { |field| "#{field.name}: #{field.name}" } + ["location: location"]).join(", ") %> }
end
-
<%- node.fields.each do |field| -%>
+
<%- if field.comment.nil? -%>
- # <%= "private " if field.is_a?(Prism::Template::FlagsField) %>attr_reader <%= field.name %>: <%= field.rbs_class %>
+ # <%= "protected " if field.is_a?(Prism::Template::FlagsField) %>attr_reader <%= field.name %>: <%= field.rbs_class %>
<%- else -%>
<%- field.each_comment_line do |line| -%>
#<%= line %>
@@ -248,9 +269,8 @@ module Prism
end
end
<%- else -%>
- attr_reader :<%= field.name -%><%= "\n private :#{field.name}" if field.is_a?(Prism::Template::FlagsField) %>
+ attr_reader :<%= field.name -%><%= "\n protected :#{field.name}" if field.is_a?(Prism::Template::FlagsField) %>
<%- end -%>
-
<%- end -%>
<%- node.fields.each do |field| -%>
<%- case field -%>
@@ -281,45 +301,9 @@ module Prism
<%- end -%>
<%- end -%>
- # def inspect(NodeInspector inspector) -> String
- def inspect(inspector = NodeInspector.new)
- inspector << inspector.header(self)
- <%- node.fields.each_with_index do |field, index| -%>
- <%- pointer, preadd = index == node.fields.length - 1 ? ["└── ", " "] : ["├── ", "│ "] -%>
- <%- case field -%>
- <%- when Prism::Template::NodeListField -%>
- inspector << "<%= pointer %><%= field.name %>: #{inspector.list("#{inspector.prefix}<%= preadd %>", <%= field.name %>)}"
- <%- when Prism::Template::ConstantListField -%>
- inspector << "<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n"
- <%- when Prism::Template::NodeField -%>
- inspector << "<%= pointer %><%= field.name %>:\n"
- inspector << inspector.child_node(<%= field.name %>, "<%= preadd %>")
- <%- when Prism::Template::OptionalNodeField -%>
- if (<%= field.name %> = self.<%= field.name %>).nil?
- inspector << "<%= pointer %><%= field.name %>: ∅\n"
- else
- inspector << "<%= pointer %><%= field.name %>:\n"
- inspector << <%= field.name %>.inspect(inspector.child_inspector("<%= preadd %>")).delete_prefix(inspector.prefix)
- end
- <%- when Prism::Template::ConstantField, Prism::Template::StringField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::IntegerField, Prism::Template::DoubleField -%>
- inspector << "<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n"
- <%- when Prism::Template::OptionalConstantField -%>
- if (<%= field.name %> = self.<%= field.name %>).nil?
- inspector << "<%= pointer %><%= field.name %>: ∅\n"
- else
- inspector << "<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n"
- end
- <%- when Prism::Template::FlagsField -%>
- <%- flag = flags.find { |flag| flag.name == field.kind }.tap { |flag| raise unless flag } -%>
- flags = [<%= flag.values.map { |value| "(\"#{value.name.downcase}\" if #{value.name.downcase}?)" }.join(", ") %>].compact
- inspector << "<%= pointer %><%= field.name %>: #{flags.empty? ? "∅" : flags.join(", ")}\n"
- <%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField -%>
- inspector << "<%= pointer %><%= field.name %>: #{inspector.location(<%= field.name %>)}\n"
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- <%- end -%>
- inspector.to_str
+ # def inspect -> String
+ def inspect
+ InspectVisitor.compose(self)
end
# Sometimes you want to check an instance of a node against a list of
@@ -349,6 +333,22 @@ module Prism
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)
+ other.is_a?(<%= node.name %>)<%= " &&" if node.fields.any? %>
+ <%- node.fields.each_with_index do |field, index| -%>
+ <%- if field.is_a?(Prism::Template::LocationField) || field.is_a?(Prism::Template::OptionalLocationField) -%>
+ (<%= field.name %>.nil? == other.<%= field.name %>.nil?)<%= " &&" if index != node.fields.length - 1 %>
+ <%- elsif field.is_a?(Prism::Template::NodeListField) || field.is_a?(Prism::Template::ConstantListField) -%>
+ (<%= field.name %>.length == other.<%= field.name %>.length) &&
+ <%= field.name %>.zip(other.<%= field.name %>).all? { |left, right| left === right }<%= " &&" if index != node.fields.length - 1 %>
+ <%- else -%>
+ (<%= field.name %> === other.<%= field.name %>)<%= " &&" if index != node.fields.length - 1 %>
+ <%- end -%>
+ <%- end -%>
+ end
end
<%- end -%>
<%- flags.each_with_index do |flag, flag_index| -%>
diff --git a/prism/templates/lib/prism/reflection.rb.erb b/prism/templates/lib/prism/reflection.rb.erb
index 13d1da33e8..3c1d61c6c1 100644
--- a/prism/templates/lib/prism/reflection.rb.erb
+++ b/prism/templates/lib/prism/reflection.rb.erb
@@ -65,14 +65,16 @@ module Prism
class OptionalLocationField < Field
end
- # A uint8 field represents an unsigned 8-bit integer value on a node. It
- # resolves to an Integer in Ruby.
- class UInt8Field < Field
+ # An integer field represents an integer value. It is used to represent the
+ # value of an integer literal, the depth of local variables, and the number
+ # of a numbered reference. It resolves to an Integer in Ruby.
+ class IntegerField < Field
end
- # A uint32 field represents an unsigned 32-bit integer value on a node. It
- # resolves to an Integer in Ruby.
- class UInt32Field < Field
+ # A float field represents a double-precision floating point value. It is
+ # used exclusively to represent the value of a floating point literal. It
+ # resolves to a Float in Ruby.
+ class FloatField < Field
end
# A flags field represents a bitset of flags on a node. It resolves to an
@@ -90,18 +92,6 @@ module Prism
end
end
- # An integer field represents an arbitrarily-sized integer value. It is used
- # exclusively to represent the value of an integer literal. It resolves to
- # an Integer in Ruby.
- class IntegerField < Field
- end
-
- # A double field represents a double-precision floating point value. It is
- # used exclusively to represent the value of a floating point literal. It
- # resolves to a Float in Ruby.
- class DoubleField < Field
- end
-
# Returns the fields for the given node.
def self.fields_for(node)
case node.type
@@ -127,17 +117,13 @@ module Prism
"LocationField.new(:#{field.name})"
when Prism::Template::OptionalLocationField
"OptionalLocationField.new(:#{field.name})"
- when Prism::Template::UInt8Field
- "UInt8Field.new(:#{field.name})"
- when Prism::Template::UInt32Field
- "UInt32Field.new(:#{field.name})"
+ when Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::IntegerField
+ "IntegerField.new(:#{field.name})"
+ when Prism::Template::DoubleField
+ "FloatField.new(:#{field.name})"
when Prism::Template::FlagsField
found = flags.find { |flag| flag.name == field.kind }.tap { |found| raise "Expected to find #{field.kind}" unless found }
"FlagsField.new(:#{field.name}, [#{found.values.map { |value| ":#{value.name.downcase}?" }.join(", ")}])"
- when Prism::Template::IntegerField
- "IntegerField.new(:#{field.name})"
- when Prism::Template::DoubleField
- "DoubleField.new(:#{field.name})"
else
raise field.class.name
end
diff --git a/prism/templates/lib/prism/serialize.rb.erb b/prism/templates/lib/prism/serialize.rb.erb
index 36d5d5432d..756821cf7d 100644
--- a/prism/templates/lib/prism/serialize.rb.erb
+++ b/prism/templates/lib/prism/serialize.rb.erb
@@ -1,5 +1,5 @@
require "stringio"
-require_relative "polyfill/string"
+require_relative "polyfill/unpack1"
module Prism
# A module responsible for deserializing parse results.
@@ -10,7 +10,7 @@ module Prism
# The minor version of prism that we are expecting to find in the serialized
# strings.
- MINOR_VERSION = 25
+ MINOR_VERSION = 29
# The patch version of prism that we are expecting to find in the serialized
# strings.
@@ -19,7 +19,7 @@ module Prism
# Deserialize the AST represented by the given string into a parse result.
def self.load(input, serialized)
input = input.dup
- source = Source.new(input)
+ source = Source.for(input)
loader = Loader.new(source, serialized)
result = loader.load_result
@@ -143,7 +143,7 @@ module Prism
length = load_varuint
lex_state = load_varuint
location = Location.new(@source, start, length)
- tokens << [Prism::Token.new(source, type, location.slice, location), lex_state]
+ tokens << [Token.new(source, type, location.slice, location), lex_state]
end
tokens
@@ -158,7 +158,7 @@ module Prism
tokens.each { |token,| token.value.force_encoding(encoding) }
raise "Expected to consume all bytes while deserializing" unless @io.eof?
- Prism::ParseResult.new(tokens, comments, magic_comments, data_loc, errors, warnings, @source)
+ LexResult.new(tokens, comments, magic_comments, data_loc, errors, warnings, @source)
end
def load_nodes
@@ -177,7 +177,7 @@ module Prism
def load_result
node, comments, magic_comments, data_loc, errors, warnings = load_nodes
- Prism::ParseResult.new(node, comments, magic_comments, data_loc, errors, warnings, @source)
+ ParseResult.new(node, comments, magic_comments, data_loc, errors, warnings, @source)
end
private
diff --git a/prism/templates/src/diagnostic.c.erb b/prism/templates/src/diagnostic.c.erb
index 42f8024551..d9e195e08f 100644
--- a/prism/templates/src/diagnostic.c.erb
+++ b/prism/templates/src/diagnostic.c.erb
@@ -91,22 +91,24 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_ARGUMENT_AFTER_BLOCK] = { "unexpected argument after a block argument", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES] = { "unexpected argument after `...`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_BARE_HASH] = { "unexpected bare hash argument", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_BLOCK_FORWARDING] = { "both a block argument and a forwarding argument; only one block is allowed", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_BLOCK_MULTI] = { "both block arg and actual block given; only one block is allowed", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ARGUMENT_CONFLICT_AMPERSAND] = { "unexpected `&`; anonymous block parameter is also used within block", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ARGUMENT_CONFLICT_STAR] = { "unexpected `*`; anonymous rest parameter is also used within block", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ARGUMENT_CONFLICT_STAR_STAR] = { "unexpected `**`; anonymous keyword rest parameter is also used within block", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_FORMAL_CLASS] = { "invalid formal argument; formal argument cannot be a class variable", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_FORMAL_CONSTANT] = { "invalid formal argument; formal argument cannot be a constant", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_FORMAL_GLOBAL] = { "invalid formal argument; formal argument cannot be a global variable", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_FORMAL_IVAR] = { "invalid formal argument; formal argument cannot be an instance variable", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_FORWARDING_UNBOUND] = { "unexpected `...` in an non-parenthesized call", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_IN] = { "unexpected `in` keyword in arguments", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_NO_FORWARDING_AMP] = { "unexpected `&`; no anonymous block parameter", 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_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 },
[PM_ERR_ARGUMENT_SPLAT_AFTER_SPLAT] = { "unexpected `*` splat argument after a `*` splat argument", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_TERM_PAREN] = { "unexpected %s; expected a `)` to close the arguments", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_UNEXPECTED_BLOCK] = { "unexpected `{` after a method call without parenthesis", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ARGUMENT_UNEXPECTED_BLOCK] = { "unexpected '{' after a method call without parenthesis", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARRAY_ELEMENT] = { "expected an element for the array", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARRAY_EXPRESSION] = { "expected an expression for the array element", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARRAY_EXPRESSION_AFTER_STAR] = { "expected an expression after `*` in the array", PM_ERROR_LEVEL_SYNTAX },
@@ -146,7 +148,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[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_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] = { "expected a `)` 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 },
[PM_ERR_DEF_RECEIVER] = { "expected a receiver for the method definition", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_DEF_RECEIVER_TERM] = { "expected a `.` or `::` after the receiver in a method definition", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_DEF_TERM] = { "expected an `end` to close the `def` statement", PM_ERROR_LEVEL_SYNTAX },
@@ -156,16 +158,16 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_EMBVAR_INVALID] = { "invalid embedded variable", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_END_UPCASE_BRACE] = { "expected a `{` after `END`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_END_UPCASE_TERM] = { "expected a `}` to close the `END` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_CONTROL] = { "invalid control escape sequence", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ESCAPE_INVALID_CONTROL] = { "Invalid escape character syntax", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT] = { "invalid control escape sequence; control cannot be repeated", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_HEXADECIMAL] = { "invalid hexadecimal escape sequence", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_META] = { "invalid meta escape sequence", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ESCAPE_INVALID_HEXADECIMAL] = { "invalid hex escape sequence", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ESCAPE_INVALID_META] = { "Invalid escape character syntax", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ESCAPE_INVALID_META_REPEAT] = { "invalid meta escape sequence; meta cannot be repeated", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ESCAPE_INVALID_UNICODE] = { "invalid Unicode escape sequence", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS] = { "invalid Unicode escape sequence; Unicode cannot be combined with control or meta flags", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL] = { "invalid Unicode escape sequence; multiple codepoints are not allowed in a character literal", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL] = { "invalid Unicode escape sequence; Multiple codepoints at single character literal are disallowed", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ESCAPE_INVALID_UNICODE_LONG] = { "invalid Unicode escape sequence; maximum length is 6 digits", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_UNICODE_TERM] = { "invalid Unicode escape sequence; needs closing `}`", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ESCAPE_INVALID_UNICODE_TERM] = { "unterminated Unicode escape", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_ARGUMENT] = { "expected an argument", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_EOL_AFTER_STATEMENT] = { "unexpected %s, expecting end-of-input", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ] = { "expected an expression after `&&=`", PM_ERROR_LEVEL_SYNTAX },
@@ -174,11 +176,12 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL] = { "expected an expression after `=`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS] = { "expected an expression after `<<`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_EXPRESSION_AFTER_LPAREN] = { "expected an expression after `(`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR] = { "expected an expression after the operator", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR] = { "unexpected %s; expected an expression after the operator", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT] = { "expected an expression after `*` splat in an argument", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH] = { "expected an expression after `**` in a hash", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_EXPRESSION_AFTER_STAR] = { "expected an expression after `*`", 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_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 },
@@ -206,31 +209,39 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_HASH_KEY] = { "unexpected %s, expecting '}' or a key in the hash literal", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_HASH_ROCKET] = { "expected a `=>` between the hash key and value", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_HASH_TERM] = { "expected a `}` to close the hash literal", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_HASH_VALUE] = { "expected a value in the hash literal", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_HEREDOC_TERM] = { "could not find a terminator for the heredoc", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_HASH_VALUE] = { "unexpected %s; expected a value in the hash literal", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_HEREDOC_IDENTIFIER] = { "unterminated here document identifier", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_HEREDOC_TERM] = { "unterminated heredoc; can't find string \"%.*s\" anywhere before EOF", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INCOMPLETE_QUESTION_MARK] = { "incomplete expression at `?`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3_0] = { "`%.*s' is not allowed as a class variable name", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3] = { "`%.*s' is not allowed as a class variable name", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INCOMPLETE_VARIABLE_CLASS] = { "'%.*s' is not allowed as a class variable name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3_0] = { "`%.*s' is not allowed as an instance variable name", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3] = { "`%.*s' is not allowed as an instance variable name", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INCOMPLETE_VARIABLE_INSTANCE] = { "'%.*s' is not allowed as an instance variable name", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INSTANCE_VARIABLE_BARE] = { "'@' without identifiers is not allowed as an instance variable name", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INVALID_BLOCK_EXIT] = { "Invalid %s", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_ESCAPE_CHARACTER] = { "Invalid escape character syntax", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INVALID_FLOAT_EXPONENT] = { "invalid exponent", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_NUMBER_BINARY] = { "invalid binary number", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_NUMBER_DECIMAL] = { "invalid decimal number", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_NUMBER_HEXADECIMAL] = { "invalid hexadecimal number", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_NUMBER_OCTAL] = { "invalid octal number", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_NUMBER_UNDERSCORE] = { "invalid underscore placement in number", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_CHARACTER] = { "invalid character 0x%X", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_LOCAL_VARIABLE_READ] = { "identifier %.*s is not valid to get", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_LOCAL_VARIABLE_WRITE] = { "identifier %.*s is not valid to set", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_NUMBER_BINARY] = { "invalid binary number; numeric literal without digits", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_NUMBER_DECIMAL] = { "invalid decimal number; numeric literal without digits", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_NUMBER_FRACTION] = { "unexpected fraction part after numeric literal", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_NUMBER_HEXADECIMAL] = { "invalid hexadecimal number; numeric literal without digits", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_NUMBER_OCTAL] = { "invalid octal number; numeric literal without digits", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER] = { "invalid underscore placement in number", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING] = { "trailing '_' in number", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_CHARACTER] = { "Invalid char '\\x%02X' in expression", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INVALID_MULTIBYTE_CHAR] = { "invalid multibyte char (%s)", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INVALID_MULTIBYTE_CHARACTER] = { "invalid multibyte character 0x%X", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INVALID_MULTIBYTE_ESCAPE] = { "invalid multibyte escape: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INVALID_PRINTABLE_CHARACTER] = { "invalid character `%c`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_PERCENT] = { "invalid `%` token", PM_ERROR_LEVEL_SYNTAX }, // TODO WHAT?
+ [PM_ERR_INVALID_PERCENT] = { "unknown type of %string", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_PERCENT_EOF] = { "unterminated quoted string meets end of file", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INVALID_RETRY_AFTER_ELSE] = { "Invalid retry after else", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INVALID_RETRY_AFTER_ENSURE] = { "Invalid retry after ensure", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INVALID_RETRY_WITHOUT_RESCUE] = { "Invalid retry without rescue", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_VARIABLE_GLOBAL_3_3_0] = { "`%.*s' is not allowed as a global variable name", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_SYMBOL] = { "invalid symbol", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_INVALID_VARIABLE_GLOBAL_3_3] = { "`%.*s' is not allowed as a global variable name", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INVALID_VARIABLE_GLOBAL] = { "'%.*s' is not allowed as a global variable name", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_INVALID_YIELD] = { "Invalid yield", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_IT_NOT_ALLOWED_NUMBERED] = { "`it` is not allowed when an numbered parameter is defined", PM_ERROR_LEVEL_SYNTAX },
@@ -239,13 +250,13 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_LAMBDA_TERM_BRACE] = { "expected a lambda block beginning with `{` to end with `}`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_LAMBDA_TERM_END] = { "expected a lambda block beginning with `do` to end with `end`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_LIST_I_LOWER_ELEMENT] = { "expected a symbol in a `%i` list", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LIST_I_LOWER_TERM] = { "expected a closing delimiter for the `%i` list", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_LIST_I_LOWER_TERM] = { "unterminated list; expected a closing delimiter for the `%i`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_LIST_I_UPPER_ELEMENT] = { "expected a symbol in a `%I` list", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LIST_I_UPPER_TERM] = { "expected a closing delimiter for the `%I` list", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_LIST_I_UPPER_TERM] = { "unterminated list; expected a closing delimiter for the `%I`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_LIST_W_LOWER_ELEMENT] = { "expected a string in a `%w` list", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LIST_W_LOWER_TERM] = { "expected a closing delimiter for the `%w` list", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_LIST_W_LOWER_TERM] = { "unterminated list; expected a closing delimiter for the `%w`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_LIST_W_UPPER_ELEMENT] = { "expected a string in a `%W` list", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LIST_W_UPPER_TERM] = { "expected a closing delimiter for the `%W` list", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_LIST_W_UPPER_TERM] = { "unterminated list; expected a closing delimiter for the `%W`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_MALLOC_FAILED] = { "failed to allocate memory", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_MIXED_ENCODING] = { "UTF-8 mixed within %s source", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_MODULE_IN_METHOD] = { "unexpected module definition in method body", PM_ERROR_LEVEL_SYNTAX },
@@ -265,6 +276,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI] = { "unexpected multiple `**` splat parameters", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PARAMETER_BLOCK_MULTI] = { "multiple block parameters; only one block is allowed", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PARAMETER_CIRCULAR] = { "circular argument reference - %.*s", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_PARAMETER_FORWARDING_AFTER_REST] = { "... after rest argument", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PARAMETER_METHOD_NAME] = { "unexpected name for a parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PARAMETER_NAME_DUPLICATED] = { "duplicated argument name", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PARAMETER_NO_DEFAULT] = { "expected a default value for the parameter", PM_ERROR_LEVEL_SYNTAX },
@@ -275,6 +287,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_PARAMETER_STAR] = { "unexpected parameter `*`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PARAMETER_UNEXPECTED_FWD] = { "unexpected `...` in parameters", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PARAMETER_WILD_LOOSE_COMMA] = { "unexpected `,` in parameters", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_PARAMETER_UNEXPECTED_NO_KW] = { "unexpected **nil; no keywords marker disallowed after keywords", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_CAPTURE_DUPLICATE] = { "duplicated variable name", 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 },
@@ -286,9 +299,12 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE] = { "expected a pattern expression after the `|` operator", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE] = { "expected a pattern expression after the range operator", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_EXPRESSION_AFTER_REST] = { "unexpected pattern expression after the `**` expression", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_HASH_KEY] = { "expected a key in the hash pattern", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_PATTERN_HASH_IMPLICIT] = { "unexpected implicit hash in pattern; use '{' to delineate", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_PATTERN_HASH_KEY] = { "unexpected %s; expected a key in the hash pattern", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_HASH_KEY_DUPLICATE] = { "duplicated key name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_HASH_KEY_LABEL] = { "expected a label as the key in the hash pattern", PM_ERROR_LEVEL_SYNTAX }, // TODO // THIS // AND // ABOVE // IS WEIRD
+ [PM_ERR_PATTERN_HASH_KEY_INTERPOLATED] = { "symbol literal with interpolation is not allowed", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_PATTERN_HASH_KEY_LABEL] = { "expected a label as the key in the hash pattern", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_PATTERN_HASH_KEY_LOCALS] = { "key must be valid as local variables", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_IDENT_AFTER_HROCKET] = { "expected an identifier after the `=>` operator", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_LABEL_AFTER_COMMA] = { "expected a label after the `,` in the hash pattern", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_REST] = { "unexpected rest pattern", PM_ERROR_LEVEL_SYNTAX },
@@ -301,7 +317,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[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_UNICODE_RANGE] = { "invalid Unicode range: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_REGEXP_UNKNOWN_OPTIONS] = { "unknown regexp %s: %.*s", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_REGEXP_TERM] = { "expected a closing delimiter for the regular expression", 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_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 },
@@ -314,18 +330,21 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_STATEMENT_PREEXE_BEGIN] = { "unexpected a `BEGIN` at a non-statement position", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_STATEMENT_UNDEF] = { "unexpected an `undef` at a non-statement position", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_STRING_CONCATENATION] = { "expected a string for concatenation", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_STRING_INTERPOLATED_TERM] = { "expected a closing delimiter for the interpolated string", PM_ERROR_LEVEL_SYNTAX },
+ [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_TERM_DYNAMIC] = { "expected a closing delimiter for the dynamic symbol", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_SYMBOL_TERM_INTERPOLATED] = { "expected a closing delimiter for the interpolated symbol", PM_ERROR_LEVEL_SYNTAX },
+ [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 },
[PM_ERR_TERNARY_EXPRESSION_FALSE] = { "expected an expression after `:` in the ternary operator", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_TERNARY_EXPRESSION_TRUE] = { "expected an expression after `?` in the ternary operator", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNDEF_ARGUMENT] = { "invalid argument being passed to `undef`; expected a bare word, constant, or symbol argument", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNARY_RECEIVER] = { "unexpected %s, expected a receiver for unary `%c`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_BLOCK_ARGUMENT] = { "block argument should not be given", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_UNEXPECTED_INDEX_BLOCK] = { "unexpected block arg given in index; blocks are not allowed in index expressions", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_UNEXPECTED_INDEX_KEYWORDS] = { "unexpected keyword arg given in index; keywords are not allowed in index expressions", 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 },
[PM_ERR_UNEXPECTED_TOKEN_IGNORE] = { "unexpected %s, ignoring it", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNTIL_TERM] = { "expected an `end` to close the `until` statement", PM_ERROR_LEVEL_SYNTAX },
@@ -347,7 +366,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_WARN_DOT_DOT_DOT_EOL] = { "... at EOL, should be parenthesized?", PM_WARNING_LEVEL_DEFAULT },
[PM_WARN_DUPLICATED_HASH_KEY] = { "key %.*s is duplicated and overwritten on line %" PRIi32, PM_WARNING_LEVEL_DEFAULT },
[PM_WARN_DUPLICATED_WHEN_CLAUSE] = { "duplicated 'when' clause with line %" PRIi32 " is ignored", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_EQUAL_IN_CONDITIONAL_3_3_0] = { "found `= literal' in conditional, should be ==", PM_WARNING_LEVEL_DEFAULT },
+ [PM_WARN_EQUAL_IN_CONDITIONAL_3_3] = { "found `= literal' in conditional, should be ==", PM_WARNING_LEVEL_DEFAULT },
[PM_WARN_EQUAL_IN_CONDITIONAL] = { "found '= literal' in conditional, should be ==", PM_WARNING_LEVEL_DEFAULT },
[PM_WARN_END_IN_METHOD] = { "END in method; use at_exit", PM_WARNING_LEVEL_DEFAULT },
[PM_WARN_FLOAT_OUT_OF_RANGE] = { "Float %.*s%s out of range", PM_WARNING_LEVEL_VERBOSE },
@@ -359,6 +378,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_WARN_KEYWORD_EOL] = { "`%.*s` at the end of line without an expression", PM_WARNING_LEVEL_VERBOSE },
[PM_WARN_LITERAL_IN_CONDITION_DEFAULT] = { "%sliteral in %s", PM_WARNING_LEVEL_DEFAULT },
[PM_WARN_LITERAL_IN_CONDITION_VERBOSE] = { "%sliteral in %s", PM_WARNING_LEVEL_VERBOSE },
+ [PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE] = { "'shareable_constant_value' is ignored unless in comment-only line", PM_WARNING_LEVEL_VERBOSE },
[PM_WARN_SHEBANG_CARRIAGE_RETURN] = { "shebang line ending with \\r may cause problems", PM_WARNING_LEVEL_DEFAULT },
[PM_WARN_UNEXPECTED_CARRIAGE_RETURN] = { "encountered \\r in middle of line, treated as a mere space", PM_WARNING_LEVEL_DEFAULT },
[PM_WARN_UNREACHABLE_STATEMENT] = { "statement not reached", PM_WARNING_LEVEL_VERBOSE },
diff --git a/prism/templates/src/token_type.c.erb b/prism/templates/src/token_type.c.erb
index 1aeecd72b2..af6a2ad6fe 100644
--- a/prism/templates/src/token_type.c.erb
+++ b/prism/templates/src/token_type.c.erb
@@ -30,7 +30,7 @@ const char *
pm_token_type_human(pm_token_type_t token_type) {
switch (token_type) {
case PM_TOKEN_EOF:
- return "end of file";
+ return "end-of-input";
case PM_TOKEN_MISSING:
return "missing token";
case PM_TOKEN_NOT_PROVIDED:
@@ -90,9 +90,9 @@ pm_token_type_human(pm_token_type_t token_type) {
case PM_TOKEN_DOT:
return "'.'";
case PM_TOKEN_DOT_DOT:
- return "'..'";
+ return "..";
case PM_TOKEN_DOT_DOT_DOT:
- return "'...'";
+ return "...";
case PM_TOKEN_EMBDOC_BEGIN:
return "'=begin'";
case PM_TOKEN_EMBDOC_END:
@@ -130,9 +130,9 @@ pm_token_type_human(pm_token_type_t token_type) {
case PM_TOKEN_GREATER_EQUAL:
return "'>='";
case PM_TOKEN_GREATER_GREATER:
- return "'>>'";
+ return ">>";
case PM_TOKEN_GREATER_GREATER_EQUAL:
- return "'>>='";
+ return ">>=";
case PM_TOKEN_HEREDOC_END:
return "heredoc ending";
case PM_TOKEN_HEREDOC_START:
@@ -258,9 +258,9 @@ pm_token_type_human(pm_token_type_t token_type) {
case PM_TOKEN_LESS_EQUAL_GREATER:
return "'<=>'";
case PM_TOKEN_LESS_LESS:
- return "'<<'";
+ return "<<";
case PM_TOKEN_LESS_LESS_EQUAL:
- return "'<<='";
+ return "<<=";
case PM_TOKEN_METHOD_NAME:
return "method name";
case PM_TOKEN_MINUS:
diff --git a/prism/templates/template.rb b/prism/templates/template.rb
index d0ce6c6643..6f79a85371 100755
--- a/prism/templates/template.rb
+++ b/prism/templates/template.rb
@@ -629,6 +629,7 @@ module Prism
"lib/prism/dispatcher.rb",
"lib/prism/dot_visitor.rb",
"lib/prism/dsl.rb",
+ "lib/prism/inspect_visitor.rb",
"lib/prism/mutation_compiler.rb",
"lib/prism/node.rb",
"lib/prism/reflection.rb",
diff --git a/prism/util/pm_integer.c b/prism/util/pm_integer.c
index 0739662e98..e523bae90b 100644
--- a/prism/util/pm_integer.c
+++ b/prism/util/pm_integer.c
@@ -135,12 +135,19 @@ karatsuba_multiply(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *
}
if (left_length * 2 <= right_length) {
- uint32_t *values = (uint32_t*) xcalloc(left_length + right_length, sizeof(uint32_t));
+ 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 = {
+ .value = 0,
+ .length = left_length,
+ .values = left_values,
+ .negative = false
+ };
+
pm_integer_t sliced_right = {
.value = 0,
.length = end_offset - start_offset,
@@ -149,7 +156,7 @@ karatsuba_multiply(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *
};
pm_integer_t product;
- karatsuba_multiply(&product, left, &sliced_right, base);
+ karatsuba_multiply(&product, &sliced_left, &sliced_right, base);
uint32_t carry = 0;
for (size_t index = 0; index < product.length; index++) {
diff --git a/prism/util/pm_strpbrk.c b/prism/util/pm_strpbrk.c
index 6c8dea1836..916a4cc3fd 100644
--- a/prism/util/pm_strpbrk.c
+++ b/prism/util/pm_strpbrk.c
@@ -9,6 +9,27 @@ pm_strpbrk_invalid_multibyte_character(pm_parser_t *parser, const uint8_t *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 *
@@ -52,7 +73,7 @@ pm_strpbrk_utf8(pm_parser_t *parser, const uint8_t *source, const uint8_t *chars
* This is the path when the encoding is ASCII-8BIT.
*/
static inline const uint8_t *
-pm_strpbrk_ascii_8bit(const uint8_t *source, const uint8_t *charset, size_t maximum) {
+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) {
@@ -60,6 +81,7 @@ pm_strpbrk_ascii_8bit(const uint8_t *source, const uint8_t *charset, size_t maxi
return source + index;
}
+ if (validate && source[index] >= 0x80) pm_strpbrk_explicit_encoding_set(parser, source, 1);
index++;
}
@@ -72,6 +94,7 @@ pm_strpbrk_ascii_8bit(const uint8_t *source, const uint8_t *charset, size_t maxi
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) {
@@ -81,7 +104,8 @@ pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t
if (source[index] < 0x80) {
index++;
} else {
- size_t width = parser->encoding->char_width(source + index, (ptrdiff_t) (maximum - index));
+ 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;
@@ -96,7 +120,7 @@ pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t
do {
index++;
- } while (index < maximum && parser->encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
+ } while (index < maximum && encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
pm_strpbrk_invalid_multibyte_character(parser, source + start, source + index);
}
@@ -113,6 +137,7 @@ pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t
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) {
@@ -122,7 +147,8 @@ pm_strpbrk_single_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t
if (source[index] < 0x80 || !validate) {
index++;
} else {
- size_t width = parser->encoding->char_width(source + index, (ptrdiff_t) (maximum - index));
+ 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;
@@ -135,7 +161,7 @@ pm_strpbrk_single_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t
do {
index++;
- } while (index < maximum && parser->encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
+ } while (index < maximum && encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
pm_strpbrk_invalid_multibyte_character(parser, source + start, source + index);
}
@@ -171,7 +197,7 @@ pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, p
} 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(source, charset, (size_t) length);
+ 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 {
diff --git a/prism/version.h b/prism/version.h
index c96fe6882f..154e967944 100644
--- a/prism/version.h
+++ b/prism/version.h
@@ -14,7 +14,7 @@
/**
* The minor version of the Prism library as an int.
*/
-#define PRISM_VERSION_MINOR 25
+#define PRISM_VERSION_MINOR 29
/**
* The patch version of the Prism library as an int.
@@ -24,6 +24,6 @@
/**
* The version of the Prism library as a constant string.
*/
-#define PRISM_VERSION "0.25.0"
+#define PRISM_VERSION "0.29.0"
#endif
diff --git a/prism_compile.c b/prism_compile.c
index 26d94e979d..9207f7a5f5 100644
--- a/prism_compile.c
+++ b/prism_compile.c
@@ -55,6 +55,13 @@
#define PUSH_SEQ(seq1, seq2) \
APPEND_LIST((seq1), (seq2))
+#define PUSH_SYNTHETIC_PUTNIL(seq, iseq) \
+ do { \
+ int lineno = ISEQ_COMPILE_DATA(iseq)->last_line; \
+ if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq)); \
+ ADD_SYNTHETIC_INSN(seq, lineno, -1, putnil); \
+ } while (0)
+
/******************************************************************************/
/* These functions compile getlocal/setlocal instructions but operate on */
/* prism locations instead of NODEs. */
@@ -130,7 +137,7 @@ pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line_no, int c
#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)
-#define PM_LOCATION_LINE_COLUMN(parser, location) \
+#define PM_LOCATION_START_LINE_COLUMN(parser, location) \
pm_newline_list_line_column(&(parser)->newline_list, (location)->start, (parser)->start_line)
static int
@@ -141,7 +148,7 @@ pm_node_line_number(const pm_parser_t *parser, const pm_node_t *node)
static int
pm_location_line_number(const pm_parser_t *parser, const pm_location_t *location) {
- return (int) PM_LOCATION_LINE_COLUMN(parser, location).line;
+ return (int) PM_LOCATION_START_LINE_COLUMN(parser, location).line;
}
/**
@@ -272,7 +279,7 @@ parse_string(const pm_scope_node_t *scope_node, const pm_string_t *string)
* creating those strings based on the flags set on the owning node.
*/
static inline VALUE
-parse_string_encoded(const pm_scope_node_t *scope_node, const pm_node_t *node, const pm_string_t *string)
+parse_string_encoded(const pm_node_t *node, const pm_string_t *string, rb_encoding *default_encoding)
{
rb_encoding *encoding;
@@ -283,7 +290,7 @@ parse_string_encoded(const pm_scope_node_t *scope_node, const pm_node_t *node, c
encoding = rb_utf8_encoding();
}
else {
- encoding = scope_node->encoding;
+ encoding = default_encoding;
}
return rb_enc_str_new((const char *) pm_string_source(string), pm_string_length(string), encoding);
@@ -294,10 +301,10 @@ parse_static_literal_string(rb_iseq_t *iseq, const pm_scope_node_t *scope_node,
{
rb_encoding *encoding;
- if (node->flags & PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING) {
+ if (node->flags & PM_STRING_FLAGS_FORCED_BINARY_ENCODING) {
encoding = rb_ascii8bit_encoding();
}
- else if (node->flags & PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING) {
+ else if (node->flags & PM_STRING_FLAGS_FORCED_UTF8_ENCODING) {
encoding = rb_utf8_encoding();
}
else {
@@ -344,91 +351,46 @@ pm_optimizable_range_item_p(const pm_node_t *node)
return (!node || PM_NODE_TYPE_P(node, PM_INTEGER_NODE) || PM_NODE_TYPE_P(node, PM_NIL_NODE));
}
-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_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
+/** Raise an error corresponding to the invalid regular expression. */
+static VALUE
+parse_regexp_error(rb_iseq_t *iseq, int32_t line_number, const char *fmt, ...)
{
- int stack_size = 0;
- size_t parts_size = parts->size;
- bool interpolated = false;
-
- if (parts_size > 0) {
- VALUE current_string = Qnil;
-
- for (size_t index = 0; index < parts_size; index++) {
- const pm_node_t *part = parts->nodes[index];
-
- if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
- const pm_string_node_t *string_node = (const pm_string_node_t *) part;
- VALUE string_value = parse_string_encoded(scope_node, (const pm_node_t *) string_node, &string_node->unescaped);
-
- if (RTEST(current_string)) {
- current_string = rb_str_concat(current_string, string_value);
- }
- else {
- current_string = string_value;
- }
- }
- else {
- interpolated = true;
-
- if (
- PM_NODE_TYPE_P(part, PM_EMBEDDED_STATEMENTS_NODE) &&
- ((const pm_embedded_statements_node_t *) part)->statements != NULL &&
- ((const pm_embedded_statements_node_t *) part)->statements->body.size == 1 &&
- PM_NODE_TYPE_P(((const pm_embedded_statements_node_t *) part)->statements->body.nodes[0], PM_STRING_NODE)
- ) {
- const pm_string_node_t *string_node = (const pm_string_node_t *) ((const pm_embedded_statements_node_t *) part)->statements->body.nodes[0];
- VALUE string_value = parse_string_encoded(scope_node, (const pm_node_t *) string_node, &string_node->unescaped);
-
- if (RTEST(current_string)) {
- current_string = rb_str_concat(current_string, string_value);
- }
- else {
- current_string = string_value;
- }
- }
- else {
- if (!RTEST(current_string)) {
- current_string = rb_enc_str_new(NULL, 0, scope_node->encoding);
- }
-
- PUSH_INSN1(ret, *node_location, putobject, rb_fstring(current_string));
- PM_COMPILE_NOT_POPPED(part);
- PUSH_INSN(ret, *node_location, dup);
- PUSH_INSN1(ret, *node_location, objtostring, new_callinfo(iseq, idTo_s, 0, VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE , NULL, FALSE));
- PUSH_INSN(ret, *node_location, anytostring);
-
- current_string = Qnil;
- stack_size += 2;
- }
- }
- }
-
- if (RTEST(current_string)) {
- current_string = rb_fstring(current_string);
+ va_list args;
+ va_start(args, fmt);
+ VALUE error = rb_syntax_error_append(Qnil, rb_iseq_path(iseq), line_number, -1, NULL, "%" PRIsVALUE, args);
+ va_end(args);
+ rb_exc_raise(error);
+}
- if (stack_size == 0 && interpolated) {
- PUSH_INSN1(ret, *node_location, putstring, current_string);
- }
- else {
- PUSH_INSN1(ret, *node_location, putobject, current_string);
- }
+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)
+{
+ // 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.
+ rb_encoding *encoding;
- current_string = Qnil;
- stack_size++;
- }
+ if (explicit_regexp_encoding != NULL) {
+ encoding = explicit_regexp_encoding;
+ }
+ else if (node->flags & PM_STRING_FLAGS_FORCED_BINARY_ENCODING) {
+ encoding = rb_ascii8bit_encoding();
+ }
+ else if (node->flags & PM_STRING_FLAGS_FORCED_UTF8_ENCODING) {
+ encoding = rb_utf8_encoding();
}
else {
- PUSH_INSN(ret, *node_location, putnil);
+ encoding = implicit_regexp_encoding;
}
- return stack_size;
+ 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));
+ return string;
}
static VALUE
-pm_static_literal_concat(const pm_node_list_t *nodes, const pm_scope_node_t *scope_node, bool top)
+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)
{
VALUE current = Qnil;
@@ -438,11 +400,28 @@ pm_static_literal_concat(const pm_node_list_t *nodes, const pm_scope_node_t *sco
switch (PM_NODE_TYPE(part)) {
case PM_STRING_NODE:
- string = parse_string_encoded(scope_node, part, &((const pm_string_node_t *) part)->unescaped);
+ if (implicit_regexp_encoding != NULL) {
+ if (top) {
+ string = parse_regexp_string_part(iseq, scope_node, part, &((const pm_string_node_t *) part)->unescaped, implicit_regexp_encoding, explicit_regexp_encoding);
+ }
+ 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));
+ }
+ }
+ else {
+ string = parse_string_encoded(part, &((const pm_string_node_t *) part)->unescaped, scope_node->encoding);
+ }
break;
case PM_INTERPOLATED_STRING_NODE:
- string = pm_static_literal_concat(&((const pm_interpolated_string_node_t *) part)->parts, scope_node, false);
+ string = pm_static_literal_concat(iseq, &((const pm_interpolated_string_node_t *) part)->parts, scope_node, implicit_regexp_encoding, explicit_regexp_encoding, false);
break;
+ case PM_EMBEDDED_STATEMENTS_NODE: {
+ const pm_embedded_statements_node_t *cast = (const pm_embedded_statements_node_t *) part;
+ string = pm_static_literal_concat(iseq, &cast->statements->body, scope_node, implicit_regexp_encoding, explicit_regexp_encoding, false);
+ break;
+ }
default:
RUBY_ASSERT(false && "unexpected node type in pm_static_literal_concat");
return Qnil;
@@ -536,21 +515,10 @@ parse_regexp_encoding(const pm_scope_node_t *scope_node, const pm_node_t *node)
return rb_enc_get_from_index(ENCINDEX_Windows_31J);
}
else {
- return scope_node->encoding;
+ return NULL;
}
}
-/** Raise an error corresponding to the invalid regular expression. */
-static VALUE
-parse_regexp_error(rb_iseq_t *iseq, int32_t line_number, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- VALUE error = rb_syntax_error_append(Qnil, rb_iseq_path(iseq), line_number, -1, NULL, "%" PRIsVALUE, args);
- va_end(args);
- rb_exc_raise(error);
-}
-
static VALUE
parse_regexp(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, VALUE string)
{
@@ -574,22 +542,144 @@ parse_regexp(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t
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)
{
- VALUE string = rb_enc_str_new((const char *) pm_string_source(unescaped), pm_string_length(unescaped), parse_regexp_encoding(scope_node, node));
+ 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);
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)
{
- VALUE string = pm_static_literal_concat(parts, scope_node, false);
- rb_enc_associate(string, parse_regexp_encoding(scope_node, 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;
+
+ VALUE string = pm_static_literal_concat(iseq, parts, scope_node, implicit_regexp_encoding, explicit_regexp_encoding, false);
return parse_regexp(iseq, scope_node, node, string);
}
+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_line_column_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)
+{
+ int stack_size = 0;
+ size_t parts_size = parts->size;
+ bool interpolated = false;
+
+ if (parts_size > 0) {
+ VALUE current_string = Qnil;
+
+ for (size_t index = 0; index < parts_size; index++) {
+ const pm_node_t *part = parts->nodes[index];
+
+ if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
+ const pm_string_node_t *string_node = (const pm_string_node_t *) part;
+ VALUE string_value;
+
+ if (implicit_regexp_encoding == NULL) {
+ string_value = parse_string_encoded(part, &string_node->unescaped, scope_node->encoding);
+ }
+ else {
+ string_value = parse_regexp_string_part(iseq, scope_node, (const pm_node_t *) string_node, &string_node->unescaped, implicit_regexp_encoding, explicit_regexp_encoding);
+ }
+
+ if (RTEST(current_string)) {
+ current_string = rb_str_concat(current_string, string_value);
+ }
+ else {
+ current_string = string_value;
+ }
+ }
+ else {
+ interpolated = true;
+
+ if (
+ PM_NODE_TYPE_P(part, PM_EMBEDDED_STATEMENTS_NODE) &&
+ ((const pm_embedded_statements_node_t *) part)->statements != NULL &&
+ ((const pm_embedded_statements_node_t *) part)->statements->body.size == 1 &&
+ PM_NODE_TYPE_P(((const pm_embedded_statements_node_t *) part)->statements->body.nodes[0], PM_STRING_NODE)
+ ) {
+ const pm_string_node_t *string_node = (const pm_string_node_t *) ((const pm_embedded_statements_node_t *) part)->statements->body.nodes[0];
+ VALUE string_value;
+
+ if (implicit_regexp_encoding == NULL) {
+ string_value = parse_string_encoded(part, &string_node->unescaped, scope_node->encoding);
+ }
+ else {
+ string_value = parse_regexp_string_part(iseq, scope_node, (const pm_node_t *) string_node, &string_node->unescaped, implicit_regexp_encoding, explicit_regexp_encoding);
+ }
+
+ if (RTEST(current_string)) {
+ current_string = rb_str_concat(current_string, string_value);
+ }
+ else {
+ current_string = string_value;
+ }
+ }
+ else {
+ if (!RTEST(current_string)) {
+ rb_encoding *encoding;
+
+ if (implicit_regexp_encoding != NULL) {
+ if (explicit_regexp_encoding != NULL) {
+ encoding = explicit_regexp_encoding;
+ }
+ else if (scope_node->parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
+ encoding = rb_ascii8bit_encoding();
+ }
+ else {
+ encoding = implicit_regexp_encoding;
+ }
+ }
+ else {
+ encoding = scope_node->encoding;
+ }
+
+ current_string = rb_enc_str_new(NULL, 0, encoding);
+ }
+
+ PUSH_INSN1(ret, *node_location, putobject, rb_fstring(current_string));
+ PM_COMPILE_NOT_POPPED(part);
+ PUSH_INSN(ret, *node_location, dup);
+ PUSH_INSN1(ret, *node_location, objtostring, new_callinfo(iseq, idTo_s, 0, VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE , NULL, FALSE));
+ PUSH_INSN(ret, *node_location, anytostring);
+
+ current_string = Qnil;
+ stack_size += 2;
+ }
+ }
+ }
+
+ if (RTEST(current_string)) {
+ current_string = rb_fstring(current_string);
+
+ if (stack_size == 0 && interpolated) {
+ PUSH_INSN1(ret, *node_location, putstring, current_string);
+ }
+ else {
+ PUSH_INSN1(ret, *node_location, putobject, current_string);
+ }
+
+ current_string = Qnil;
+ stack_size++;
+ }
+ }
+ else {
+ PUSH_INSN(ret, *node_location, putnil);
+ }
+
+ return stack_size;
+}
+
static void
pm_compile_regexp_dynamic(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list_t *parts, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
- int length = pm_interpolated_node_compile(iseq, parts, node_location, ret, popped, scope_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);
PUSH_INSN2(ret, *node_location, toregexp, INT2FIX(parse_regexp_flags(node) & 0xFF), INT2FIX(length));
}
@@ -686,13 +776,13 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
return parse_regexp_concat(iseq, scope_node, (const pm_node_t *) cast, &cast->parts);
}
case PM_INTERPOLATED_STRING_NODE: {
- VALUE string = pm_static_literal_concat(&((const pm_interpolated_string_node_t *) node)->parts, scope_node, false);
+ 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);
return pm_static_literal_string(iseq, string, line_number);
}
case PM_INTERPOLATED_SYMBOL_NODE: {
const pm_interpolated_symbol_node_t *cast = (const pm_interpolated_symbol_node_t *) node;
- VALUE string = pm_static_literal_concat(&cast->parts, scope_node, true);
+ VALUE string = pm_static_literal_concat(iseq, &cast->parts, scope_node, NULL, NULL, true);
return ID2SYM(rb_intern_str(string));
}
@@ -730,6 +820,28 @@ 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)
+{
+ 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);
+
+ return (rb_code_location_t) {
+ .beg_pos = { .lineno = start_location.line, .column = start_location.column },
+ .end_pos = { .lineno = end_location.line, .column = end_location.column }
+ };
+}
+
+/**
+ * A macro for determining if we should go through the work of adding branch
+ * coverage to the current iseq. We check this manually each time because we
+ * want to avoid the overhead of creating rb_code_location_t objects.
+ */
+#define PM_BRANCH_COVERAGE_P(iseq) (ISEQ_COVERAGE(iseq) && ISEQ_BRANCH_COVERAGE(iseq))
+
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);
@@ -882,7 +994,7 @@ again:
* Compile an if or unless node.
*/
static void
-pm_compile_conditional(rb_iseq_t *iseq, const pm_line_column_t *line_column, const pm_statements_node_t *statements, const pm_node_t *consequent, const pm_node_t *predicate, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
+pm_compile_conditional(rb_iseq_t *iseq, const pm_line_column_t *line_column, pm_node_type_t type, const pm_node_t *node, const pm_statements_node_t *statements, const pm_node_t *consequent, const pm_node_t *predicate, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
const pm_line_column_t location = *line_column;
LABEL *then_label = NEW_LABEL(location.line);
@@ -891,20 +1003,47 @@ pm_compile_conditional(rb_iseq_t *iseq, const pm_line_column_t *line_column, con
pm_compile_branch_condition(iseq, ret, predicate, then_label, else_label, false, scope_node);
+ rb_code_location_t conditional_location;
+ VALUE branches = Qfalse;
+
+ if (then_label->refcnt && else_label->refcnt && PM_BRANCH_COVERAGE_P(iseq)) {
+ conditional_location = pm_code_location(scope_node, node);
+ branches = decl_branch_base(iseq, PTR2NUM(node), &conditional_location, type == PM_IF_NODE ? "if" : "unless");
+ }
+
if (then_label->refcnt) {
PUSH_LABEL(ret, then_label);
DECL_ANCHOR(then_seq);
INIT_ANCHOR(then_seq);
- if (statements) {
+ if (statements != NULL) {
pm_compile_node(iseq, (const pm_node_t *) statements, then_seq, popped, scope_node);
}
else if (!popped) {
- PUSH_INSN(then_seq, location, putnil);
+ PUSH_SYNTHETIC_PUTNIL(then_seq, iseq);
}
if (else_label->refcnt) {
+ // Establish branch coverage for the then block.
+ if (PM_BRANCH_COVERAGE_P(iseq)) {
+ rb_code_location_t branch_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);
+ 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 }
+ };
+ } else {
+ branch_location = conditional_location;
+ }
+
+ add_trace_branch_coverage(iseq, ret, &branch_location, branch_location.beg_pos.column, 0, type == PM_IF_NODE ? "then" : "else", branches);
+ }
+
end_label = NEW_LABEL(location.line);
PUSH_INSNL(then_seq, location, jump, end_label);
if (!popped) PUSH_INSN(then_seq, location, pop);
@@ -919,11 +1058,27 @@ pm_compile_conditional(rb_iseq_t *iseq, const pm_line_column_t *line_column, con
DECL_ANCHOR(else_seq);
INIT_ANCHOR(else_seq);
- if (consequent) {
- pm_compile_node(iseq, (const pm_node_t *) consequent, else_seq, popped, scope_node);
+ if (consequent != NULL) {
+ pm_compile_node(iseq, consequent, else_seq, popped, scope_node);
}
else if (!popped) {
- PUSH_INSN(else_seq, location, putnil);
+ PUSH_SYNTHETIC_PUTNIL(else_seq, iseq);
+ }
+
+ // Establish branch coverage for the else block.
+ if (then_label->refcnt && PM_BRANCH_COVERAGE_P(iseq)) {
+ rb_code_location_t branch_location;
+
+ if (consequent == NULL) {
+ branch_location = conditional_location;
+ } else if (PM_NODE_TYPE_P(consequent, PM_ELSE_NODE)) {
+ const pm_else_node_t *else_node = (const pm_else_node_t *) consequent;
+ branch_location = pm_code_location(scope_node, else_node->statements != NULL ? ((const pm_node_t *) else_node->statements) : (const pm_node_t *) else_node);
+ } else {
+ branch_location = pm_code_location(scope_node, (const pm_node_t *) consequent);
+ }
+
+ add_trace_branch_coverage(iseq, ret, &branch_location, branch_location.beg_pos.column, 1, type == PM_IF_NODE ? "else" : "then", branches);
}
PUSH_SEQ(ret, else_seq);
@@ -940,7 +1095,7 @@ pm_compile_conditional(rb_iseq_t *iseq, const pm_line_column_t *line_column, con
* Compile a while or until loop.
*/
static void
-pm_compile_loop(rb_iseq_t *iseq, const pm_line_column_t *line_column, pm_node_flags_t flags, enum pm_node_type type, const pm_statements_node_t *statements, const pm_node_t *predicate, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
+pm_compile_loop(rb_iseq_t *iseq, const pm_line_column_t *line_column, pm_node_flags_t flags, enum pm_node_type type, const pm_node_t *node, const pm_statements_node_t *statements, const pm_node_t *predicate, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
const pm_line_column_t location = *line_column;
@@ -976,9 +1131,19 @@ pm_compile_loop(rb_iseq_t *iseq, const pm_line_column_t *line_column, pm_node_fl
if (tmp_label) PUSH_LABEL(ret, tmp_label);
PUSH_LABEL(ret, redo_label);
- if (statements != NULL) PM_COMPILE_POPPED((const pm_node_t *) statements);
+ // Establish branch coverage for the loop.
+ if (PM_BRANCH_COVERAGE_P(iseq)) {
+ rb_code_location_t loop_location = pm_code_location(scope_node, node);
+ VALUE branches = decl_branch_base(iseq, PTR2NUM(node), &loop_location, type == PM_WHILE_NODE ? "while" : "until");
+
+ rb_code_location_t branch_location = statements != NULL ? pm_code_location(scope_node, (const pm_node_t *) statements) : loop_location;
+ add_trace_branch_coverage(iseq, ret, &branch_location, branch_location.beg_pos.column, 0, "body", branches);
+ }
+
+ if (statements != NULL) PM_COMPILE_POPPED((const pm_node_t *) statements);
PUSH_LABEL(ret, next_label);
+
if (type == PM_WHILE_NODE) {
pm_compile_branch_condition(iseq, ret, predicate, redo_label, end_label, popped, scope_node);
}
@@ -1572,7 +1737,7 @@ pm_compile_index_operator_write_node(rb_iseq_t *iseq, const pm_index_operator_wr
PUSH_SEND_R(ret, location, idAREF, INT2FIX(argc), NULL, INT2FIX(flag & ~(VM_CALL_ARGS_SPLAT_MUT | VM_CALL_KW_SPLAT_MUT)), keywords);
PM_COMPILE_NOT_POPPED(node->value);
- ID id_operator = pm_constant_id_lookup(scope_node, node->operator);
+ ID id_operator = pm_constant_id_lookup(scope_node, node->binary_operator);
PUSH_SEND(ret, location, id_operator, INT2FIX(1));
if (!popped) {
@@ -2808,19 +2973,81 @@ pm_scope_node_destroy(pm_scope_node_t *scope_node)
}
}
+/**
+ * We need to put the label "retry_end_l" immediately after the last "send"
+ * instruction. This because vm_throw checks if the break cont is equal to the
+ * index of next insn of the "send". (Otherwise, it is considered
+ * "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
+ *
+ * Normally, "send" instruction is at the last. However, qcall under branch
+ * coverage measurement adds some instructions after the "send".
+ *
+ * Note that "invokesuper" appears instead of "send".
+ */
+static void
+pm_compile_retry_end_label(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *retry_end_l)
+{
+ INSN *iobj;
+ LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
+ iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
+ while (INSN_OF(iobj) != BIN(send) && INSN_OF(iobj) != BIN(invokesuper)) {
+ iobj = (INSN*) get_prev_insn(iobj);
+ }
+ ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
+
+ // LINK_ANCHOR has a pointer to the last element, but
+ // ELEM_INSERT_NEXT does not update it even if we add an insn to the
+ // last of LINK_ANCHOR. So this updates it manually.
+ if (&iobj->link == LAST_ELEMENT(ret)) {
+ ret->last = (LINK_ELEMENT*) retry_end_l;
+ }
+}
+
+/**
+ * Compile a call node into the given iseq.
+ */
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;
- const pm_line_column_t location = PM_LOCATION_LINE_COLUMN(scope_node->parser, message_loc);
+ const pm_line_column_t location = PM_LOCATION_START_LINE_COLUMN(scope_node->parser, message_loc);
LABEL *else_label = NEW_LABEL(location.line);
LABEL *end_label = NEW_LABEL(location.line);
+ LABEL *retry_end_l = NEW_LABEL(location.line);
+
+ VALUE branches = Qfalse;
+ rb_code_location_t code_location = { 0 };
+ int node_id = location.column;
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
+ };
+
+ 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]);
+
+ 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);
+
+ code_location = (rb_code_location_t) {
+ .beg_pos = { .lineno = start_location.line, .column = start_location.column },
+ .end_pos = { .lineno = end_location.line, .column = end_location.column }
+ };
+
+ branches = decl_branch_base(iseq, PTR2NUM(call_node), &code_location, "&.");
+ }
+
PUSH_INSN(ret, location, dup);
PUSH_INSNL(ret, location, branchnil, else_label);
+
+ add_trace_branch_coverage(iseq, ret, &code_location, node_id, 0, "then", branches);
}
int flags = 0;
@@ -2836,10 +3063,6 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c
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));
pm_scope_node_destroy(&next_scope_node);
-
- if (ISEQ_BODY(block_iseq)->catch_table) {
- PUSH_CATCH_ENTRY(CATCH_TYPE_BREAK, start, end_label, block_iseq, end_label);
- }
ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq;
}
else {
@@ -2884,12 +3107,15 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c
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);
+ PUSH_CATCH_ENTRY(CATCH_TYPE_BREAK, start, retry_end_l, block_iseq, retry_end_l);
+ }
+
if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
PUSH_INSNL(ret, location, jump, end_label);
PUSH_LABEL(ret, else_label);
- }
-
- if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) || (block_iseq && ISEQ_BODY(block_iseq)->catch_table)) {
+ add_trace_branch_coverage(iseq, ret, &code_location, node_id, 1, "else", branches);
PUSH_LABEL(ret, end_label);
}
@@ -3075,7 +3301,7 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_c
}
case PM_CONSTANT_PATH_NODE: {
const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, ((const pm_constant_read_node_t *) cast->child)->name));
+ VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
if (cast->parent != NULL) {
if (!lfinish[1]) lfinish[1] = NEW_LABEL(location.line);
@@ -3371,8 +3597,11 @@ pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, st_tabl
if (rest->expression != NULL) {
RUBY_ASSERT(PM_NODE_TYPE_P(rest->expression, PM_REQUIRED_PARAMETER_NODE));
- pm_insert_local_index(((const pm_required_parameter_node_t *) rest->expression)->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- local_index++;
+
+ if (!PM_NODE_FLAG_P(rest->expression, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
+ pm_insert_local_index(((const pm_required_parameter_node_t *) rest->expression)->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ local_index++;
+ }
}
}
@@ -3380,8 +3609,10 @@ pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, st_tabl
const pm_node_t *right = node->rights.nodes[index];
if (PM_NODE_TYPE_P(right, PM_REQUIRED_PARAMETER_NODE)) {
- pm_insert_local_index(((const pm_required_parameter_node_t *) right)->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- local_index++;
+ if (!PM_NODE_FLAG_P(right, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
+ pm_insert_local_index(((const pm_required_parameter_node_t *) right)->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ local_index++;
+ }
}
else {
RUBY_ASSERT(PM_NODE_TYPE_P(right, PM_MULTI_TARGET_NODE));
@@ -3574,7 +3805,7 @@ pm_multi_target_state_update(pm_multi_target_state_t *state)
previous = current;
current = current->next;
- free(previous);
+ xfree(previous);
}
}
@@ -3686,7 +3917,7 @@ pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *cons
// for I::J in []; end
//
const pm_constant_path_target_node_t *cast = (const pm_constant_path_target_node_t *) node;
- ID name = pm_constant_id_lookup(scope_node, ((const pm_constant_read_node_t *) cast->child)->name);
+ ID name = pm_constant_id_lookup(scope_node, cast->name);
if (cast->parent != NULL) {
pm_compile_node(iseq, cast->parent, parents, false, scope_node);
@@ -4182,7 +4413,7 @@ pm_opt_aset_with_p(const rb_iseq_t *iseq, const pm_call_node_t *node)
static void
pm_compile_constant_read(rb_iseq_t *iseq, VALUE name, const pm_location_t *name_loc, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node)
{
- const pm_line_column_t location = PM_LOCATION_LINE_COLUMN(scope_node->parser, name_loc);
+ const pm_line_column_t location = PM_LOCATION_START_LINE_COLUMN(scope_node->parser, name_loc);
if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
ISEQ_BODY(iseq)->ic_size++;
@@ -4216,7 +4447,7 @@ pm_constant_path_parts(const pm_node_t *node, const pm_scope_node_t *scope_node)
}
case PM_CONSTANT_PATH_NODE: {
const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, ((const pm_constant_read_node_t *) cast->child)->name));
+ VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
rb_ary_unshift(parts, name);
if (cast->parent == NULL) {
@@ -4254,7 +4485,7 @@ pm_compile_constant_path(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *co
}
case PM_CONSTANT_PATH_NODE: {
const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, ((const pm_constant_read_node_t *) cast->child)->name));
+ VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
if (cast->parent == NULL) {
PUSH_INSN(body, location, pop);
@@ -4332,7 +4563,496 @@ pm_compile_case_node_dispatch(rb_iseq_t *iseq, VALUE dispatch, const pm_node_t *
return dispatch;
}
-/*
+/**
+ * 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)
+{
+ switch (PM_NODE_TYPE(node)) {
+ case PM_TRUE_NODE:
+ case PM_FALSE_NODE:
+ case PM_NIL_NODE:
+ case PM_SYMBOL_NODE:
+ case PM_REGULAR_EXPRESSION_NODE:
+ case PM_SOURCE_LINE_NODE:
+ case PM_INTEGER_NODE:
+ case PM_FLOAT_NODE:
+ case PM_RATIONAL_NODE:
+ case PM_IMAGINARY_NODE:
+ case PM_SOURCE_ENCODING_NODE:
+ return pm_static_literal_value(iseq, node, scope_node);
+ case PM_STRING_NODE:
+ return parse_static_literal_string(iseq, scope_node, node, &((const pm_string_node_t *) node)->unescaped);
+ case PM_SOURCE_FILE_NODE:
+ return pm_source_file_value((const pm_source_file_node_t *) node, scope_node);
+ case PM_ARRAY_NODE: {
+ const pm_array_node_t *cast = (const pm_array_node_t *) node;
+ VALUE result = rb_ary_new_capa(cast->elements.size);
+
+ for (size_t index = 0; index < cast->elements.size; index++) {
+ VALUE element = pm_compile_shareable_constant_literal(iseq, cast->elements.nodes[index], scope_node);
+ if (element == Qundef) return Qundef;
+
+ rb_ary_push(result, element);
+ }
+
+ return rb_ractor_make_shareable(result);
+ }
+ 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);
+
+ for (size_t index = 0; index < cast->elements.size; index++) {
+ const pm_node_t *element = cast->elements.nodes[index];
+ if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE)) return Qundef;
+
+ const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) element;
+
+ VALUE key = pm_compile_shareable_constant_literal(iseq, assoc->key, scope_node);
+ if (key == Qundef) return Qundef;
+
+ VALUE value = pm_compile_shareable_constant_literal(iseq, assoc->value, scope_node);
+ if (value == Qundef) return Qundef;
+
+ rb_hash_aset(result, key, value);
+ }
+
+ return rb_ractor_make_shareable(result);
+ }
+ default:
+ return Qundef;
+ }
+}
+
+/**
+ * Compile the instructions for pushing the value that will be written to a
+ * shared constant.
+ */
+static void
+pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_flags_t shareability, VALUE path, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, bool top)
+{
+ VALUE literal = pm_compile_shareable_constant_literal(iseq, node, scope_node);
+ if (literal != Qundef) {
+ const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node);
+ PUSH_INSN1(ret, location, putobject, literal);
+ return;
+ }
+
+ const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node);
+ switch (PM_NODE_TYPE(node)) {
+ case PM_ARRAY_NODE: {
+ const pm_array_node_t *cast = (const pm_array_node_t *) node;
+
+ if (top) {
+ PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ }
+
+ for (size_t index = 0; index < cast->elements.size; index++) {
+ pm_compile_shareable_constant_value(iseq, cast->elements.nodes[index], shareability, path, ret, scope_node, false);
+ }
+
+ PUSH_INSN1(ret, location, newarray, INT2FIX(cast->elements.size));
+
+ if (top) {
+ ID method_id = (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY) ? rb_intern("make_shareable_copy") : rb_intern("make_shareable");
+ PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
+ }
+
+ return;
+ }
+ case PM_HASH_NODE: {
+ const pm_hash_node_t *cast = (const pm_hash_node_t *) node;
+
+ if (top) {
+ PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ }
+
+ for (size_t index = 0; index < cast->elements.size; index++) {
+ const pm_node_t *element = cast->elements.nodes[index];
+
+ if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE)) {
+ COMPILE_ERROR(ERROR_ARGS "Ractor constant writes do not support **");
+ }
+
+ const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) element;
+ pm_compile_shareable_constant_value(iseq, assoc->key, shareability, path, ret, scope_node, false);
+ pm_compile_shareable_constant_value(iseq, assoc->value, shareability, path, ret, scope_node, false);
+ }
+
+ PUSH_INSN1(ret, location, newhash, INT2FIX(cast->elements.size * 2));
+
+ if (top) {
+ ID method_id = (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY) ? rb_intern("make_shareable_copy") : rb_intern("make_shareable");
+ PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
+ }
+
+ return;
+ }
+ default: {
+ DECL_ANCHOR(value_seq);
+ INIT_ANCHOR(value_seq);
+
+ pm_compile_node(iseq, node, value_seq, false, scope_node);
+ if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
+ PUSH_SEND_WITH_FLAG(value_seq, location, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
+ }
+
+ if (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL) {
+ PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ PUSH_SEQ(ret, value_seq);
+ PUSH_INSN1(ret, location, putobject, path);
+ PUSH_SEND_WITH_FLAG(ret, location, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
+ }
+ else if (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY) {
+ if (top) PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ PUSH_SEQ(ret, value_seq);
+ if (top) PUSH_SEND_WITH_FLAG(ret, location, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
+ }
+ else if (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING) {
+ if (top) PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ PUSH_SEQ(ret, value_seq);
+ if (top) PUSH_SEND_WITH_FLAG(ret, location, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
+ }
+
+ break;
+ }
+ }
+}
+
+/**
+ * Compile a constant write node, either in the context of a ractor pragma or
+ * not.
+ */
+static void
+pm_compile_constant_write_node(rb_iseq_t *iseq, const pm_constant_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
+{
+ const pm_line_column_t location = *node_location;
+ ID name_id = pm_constant_id_lookup(scope_node, node->name);
+
+ if (shareability != 0) {
+ pm_compile_shareable_constant_value(iseq, node->value, shareability, rb_id2str(name_id), ret, scope_node, true);
+ }
+ else {
+ PM_COMPILE_NOT_POPPED(node->value);
+ }
+
+ if (!popped) PUSH_INSN(ret, location, dup);
+ PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
+ PUSH_INSN1(ret, location, setconstant, ID2SYM(name_id));
+}
+
+/**
+ * Compile a constant and write node, either in the context of a ractor pragma
+ * or not.
+ */
+static void
+pm_compile_constant_and_write_node(rb_iseq_t *iseq, const pm_constant_and_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
+{
+ const pm_line_column_t location = *node_location;
+
+ VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, node->name));
+ LABEL *end_label = NEW_LABEL(location.line);
+
+ pm_compile_constant_read(iseq, name, &node->name_loc, ret, scope_node);
+ if (!popped) PUSH_INSN(ret, location, dup);
+
+ PUSH_INSNL(ret, location, branchunless, end_label);
+ if (!popped) PUSH_INSN(ret, location, pop);
+
+ if (shareability != 0) {
+ pm_compile_shareable_constant_value(iseq, node->value, shareability, name, ret, scope_node, true);
+ }
+ else {
+ PM_COMPILE_NOT_POPPED(node->value);
+ }
+
+ if (!popped) PUSH_INSN(ret, location, dup);
+ PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
+ PUSH_INSN1(ret, location, setconstant, name);
+ PUSH_LABEL(ret, end_label);
+}
+
+/**
+ * Compile a constant or write node, either in the context of a ractor pragma or
+ * not.
+ */
+static void
+pm_compile_constant_or_write_node(rb_iseq_t *iseq, const pm_constant_or_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
+{
+ const pm_line_column_t location = *node_location;
+ VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, node->name));
+
+ LABEL *set_label = NEW_LABEL(location.line);
+ LABEL *end_label = NEW_LABEL(location.line);
+
+ PUSH_INSN(ret, location, putnil);
+ PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_CONST), name, Qtrue);
+ PUSH_INSNL(ret, location, branchunless, set_label);
+
+ pm_compile_constant_read(iseq, name, &node->name_loc, ret, scope_node);
+ if (!popped) PUSH_INSN(ret, location, dup);
+
+ PUSH_INSNL(ret, location, branchif, end_label);
+ if (!popped) PUSH_INSN(ret, location, pop);
+ PUSH_LABEL(ret, set_label);
+
+ if (shareability != 0) {
+ pm_compile_shareable_constant_value(iseq, node->value, shareability, name, ret, scope_node, true);
+ }
+ else {
+ PM_COMPILE_NOT_POPPED(node->value);
+ }
+
+ if (!popped) PUSH_INSN(ret, location, dup);
+ PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
+ PUSH_INSN1(ret, location, setconstant, name);
+ PUSH_LABEL(ret, end_label);
+}
+
+/**
+ * Compile a constant operator write node, either in the context of a ractor
+ * pragma or not.
+ */
+static void
+pm_compile_constant_operator_write_node(rb_iseq_t *iseq, const pm_constant_operator_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
+{
+ const pm_line_column_t location = *node_location;
+
+ VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, node->name));
+ ID method_id = pm_constant_id_lookup(scope_node, node->binary_operator);
+
+ pm_compile_constant_read(iseq, name, &node->name_loc, ret, scope_node);
+
+ if (shareability != 0) {
+ pm_compile_shareable_constant_value(iseq, node->value, shareability, name, ret, scope_node, true);
+ }
+ else {
+ PM_COMPILE_NOT_POPPED(node->value);
+ }
+
+ PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2NUM(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
+ if (!popped) PUSH_INSN(ret, location, dup);
+
+ PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
+ PUSH_INSN1(ret, location, setconstant, name);
+}
+
+/**
+ * Creates a string that is used in ractor error messages to describe the
+ * constant path being written.
+ */
+static VALUE
+pm_constant_path_path(const pm_constant_path_node_t *node, const pm_scope_node_t *scope_node)
+{
+ VALUE parts = rb_ary_new();
+ rb_ary_push(parts, rb_id2str(pm_constant_id_lookup(scope_node, node->name)));
+
+ const pm_node_t *current = node->parent;
+ while (current != NULL && PM_NODE_TYPE_P(current, PM_CONSTANT_PATH_NODE)) {
+ const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) current;
+ rb_ary_unshift(parts, rb_id2str(pm_constant_id_lookup(scope_node, cast->name)));
+ current = cast->parent;
+ }
+
+ if (current == NULL) {
+ rb_ary_unshift(parts, rb_id2str(idNULL));
+ }
+ else if (PM_NODE_TYPE_P(current, PM_CONSTANT_READ_NODE)) {
+ rb_ary_unshift(parts, rb_id2str(pm_constant_id_lookup(scope_node, ((const pm_constant_read_node_t *) current)->name)));
+ }
+ else {
+ rb_ary_unshift(parts, rb_str_new_cstr("..."));
+ }
+
+ return rb_ary_join(parts, rb_str_new_cstr("::"));
+}
+
+/**
+ * Compile a constant path write node, either in the context of a ractor pragma
+ * or not.
+ */
+static void
+pm_compile_constant_path_write_node(rb_iseq_t *iseq, const pm_constant_path_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
+{
+ const pm_line_column_t location = *node_location;
+ const pm_constant_path_node_t *target = node->target;
+ VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, target->name));
+
+ if (target->parent) {
+ PM_COMPILE_NOT_POPPED((const pm_node_t *) target->parent);
+ }
+ else {
+ PUSH_INSN1(ret, location, putobject, rb_cObject);
+ }
+
+ if (shareability != 0) {
+ pm_compile_shareable_constant_value(iseq, node->value, shareability, pm_constant_path_path(node->target, scope_node), ret, scope_node, true);
+ }
+ else {
+ PM_COMPILE_NOT_POPPED(node->value);
+ }
+
+ if (!popped) {
+ PUSH_INSN(ret, location, swap);
+ PUSH_INSN1(ret, location, topn, INT2FIX(1));
+ }
+
+ PUSH_INSN(ret, location, swap);
+ PUSH_INSN1(ret, location, setconstant, name);
+}
+
+/**
+ * Compile a constant path and write node, either in the context of a ractor
+ * pragma or not.
+ */
+static void
+pm_compile_constant_path_and_write_node(rb_iseq_t *iseq, const pm_constant_path_and_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
+{
+ const pm_line_column_t location = *node_location;
+ const pm_constant_path_node_t *target = node->target;
+
+ VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, target->name));
+ LABEL *lfin = NEW_LABEL(location.line);
+
+ if (target->parent) {
+ PM_COMPILE_NOT_POPPED(target->parent);
+ }
+ else {
+ PUSH_INSN1(ret, location, putobject, rb_cObject);
+ }
+
+ PUSH_INSN(ret, location, dup);
+ PUSH_INSN1(ret, location, putobject, Qtrue);
+ PUSH_INSN1(ret, location, getconstant, name);
+
+ if (!popped) PUSH_INSN(ret, location, dup);
+ PUSH_INSNL(ret, location, branchunless, lfin);
+
+ if (!popped) PUSH_INSN(ret, location, pop);
+
+ if (shareability != 0) {
+ pm_compile_shareable_constant_value(iseq, node->value, shareability, pm_constant_path_path(node->target, scope_node), ret, scope_node, true);
+ }
+ else {
+ PM_COMPILE_NOT_POPPED(node->value);
+ }
+
+ if (popped) {
+ PUSH_INSN1(ret, location, topn, INT2FIX(1));
+ }
+ else {
+ PUSH_INSN1(ret, location, dupn, INT2FIX(2));
+ PUSH_INSN(ret, location, swap);
+ }
+
+ PUSH_INSN1(ret, location, setconstant, name);
+ PUSH_LABEL(ret, lfin);
+
+ if (!popped) PUSH_INSN(ret, location, swap);
+ PUSH_INSN(ret, location, pop);
+}
+
+/**
+ * Compile a constant path or write node, either in the context of a ractor
+ * pragma or not.
+ */
+static void
+pm_compile_constant_path_or_write_node(rb_iseq_t *iseq, const pm_constant_path_or_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
+{
+ const pm_line_column_t location = *node_location;
+ const pm_constant_path_node_t *target = node->target;
+
+ VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, target->name));
+ LABEL *lassign = NEW_LABEL(location.line);
+ LABEL *lfin = NEW_LABEL(location.line);
+
+ if (target->parent) {
+ PM_COMPILE_NOT_POPPED(target->parent);
+ }
+ else {
+ PUSH_INSN1(ret, location, putobject, rb_cObject);
+ }
+
+ PUSH_INSN(ret, location, dup);
+ PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_CONST_FROM), name, Qtrue);
+ PUSH_INSNL(ret, location, branchunless, lassign);
+
+ PUSH_INSN(ret, location, dup);
+ PUSH_INSN1(ret, location, putobject, Qtrue);
+ PUSH_INSN1(ret, location, getconstant, name);
+
+ if (!popped) PUSH_INSN(ret, location, dup);
+ PUSH_INSNL(ret, location, branchif, lfin);
+
+ if (!popped) PUSH_INSN(ret, location, pop);
+ PUSH_LABEL(ret, lassign);
+
+ if (shareability != 0) {
+ pm_compile_shareable_constant_value(iseq, node->value, shareability, pm_constant_path_path(node->target, scope_node), ret, scope_node, true);
+ }
+ else {
+ PM_COMPILE_NOT_POPPED(node->value);
+ }
+
+ if (popped) {
+ PUSH_INSN1(ret, location, topn, INT2FIX(1));
+ }
+ else {
+ PUSH_INSN1(ret, location, dupn, INT2FIX(2));
+ PUSH_INSN(ret, location, swap);
+ }
+
+ PUSH_INSN1(ret, location, setconstant, name);
+ PUSH_LABEL(ret, lfin);
+
+ if (!popped) PUSH_INSN(ret, location, swap);
+ PUSH_INSN(ret, location, pop);
+}
+
+/**
+ * Compile a constant path operator write node, either in the context of a
+ * ractor pragma or not.
+ */
+static void
+pm_compile_constant_path_operator_write_node(rb_iseq_t *iseq, const pm_constant_path_operator_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
+{
+ const pm_line_column_t location = *node_location;
+ const pm_constant_path_node_t *target = node->target;
+
+ ID method_id = pm_constant_id_lookup(scope_node, node->binary_operator);
+ VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, target->name));
+
+ if (target->parent) {
+ PM_COMPILE_NOT_POPPED(target->parent);
+ }
+ else {
+ PUSH_INSN1(ret, location, putobject, rb_cObject);
+ }
+
+ PUSH_INSN(ret, location, dup);
+ PUSH_INSN1(ret, location, putobject, Qtrue);
+ PUSH_INSN1(ret, location, getconstant, name);
+
+ if (shareability != 0) {
+ pm_compile_shareable_constant_value(iseq, node->value, shareability, pm_constant_path_path(node->target, scope_node), ret, scope_node, true);
+ }
+ else {
+ PM_COMPILE_NOT_POPPED(node->value);
+ }
+
+ PUSH_CALL(ret, location, method_id, INT2FIX(1));
+ PUSH_INSN(ret, location, swap);
+
+ if (!popped) {
+ PUSH_INSN1(ret, location, topn, INT2FIX(1));
+ PUSH_INSN(ret, location, swap);
+ }
+
+ PUSH_INSN1(ret, location, setconstant, name);
+}
+
+/**
* Compiles a prism node into instruction sequences.
*
* iseq - The current instruction sequence object (used for locals)
@@ -4349,14 +5069,16 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(parser, node);
int lineno = (int) location.line;
- if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_NEWLINE) && ISEQ_COMPILE_DATA(iseq)->last_line != lineno) {
- int event = RUBY_EVENT_LINE;
+ if (!PM_NODE_TYPE_P(node, PM_RETURN_NODE) || !PM_NODE_FLAG_P(node, PM_RETURN_NODE_FLAGS_REDUNDANT) || ((const pm_return_node_t *) node)->arguments != NULL) {
+ if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_NEWLINE) && ISEQ_COMPILE_DATA(iseq)->last_line != lineno) {
+ int event = RUBY_EVENT_LINE;
- ISEQ_COMPILE_DATA(iseq)->last_line = lineno;
- if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
- event |= RUBY_EVENT_COVERAGE_LINE;
+ ISEQ_COMPILE_DATA(iseq)->last_line = lineno;
+ if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
+ event |= RUBY_EVENT_COVERAGE_LINE;
+ }
+ PUSH_TRACE(ret, event);
}
- PUSH_TRACE(ret, event);
}
switch (PM_NODE_TYPE(node)) {
@@ -4820,7 +5542,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_SEND_WITH_FLAG(ret, location, id_read_name, INT2FIX(0), INT2FIX(flag));
PM_COMPILE_NOT_POPPED(cast->value);
- ID id_operator = pm_constant_id_lookup(scope_node, cast->operator);
+ ID id_operator = pm_constant_id_lookup(scope_node, cast->binary_operator);
PUSH_SEND(ret, location, id_operator, INT2FIX(1));
if (!popped) {
@@ -4863,6 +5585,16 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// compare all of the various when clauses to the predicate. If we
// don't, then it's basically an if-elsif-else chain.
if (cast->predicate == NULL) {
+ // Establish branch coverage for the case node.
+ VALUE branches = Qfalse;
+ rb_code_location_t case_location = { 0 };
+ int branch_id = 0;
+
+ if (PM_BRANCH_COVERAGE_P(iseq)) {
+ case_location = pm_code_location(scope_node, (const pm_node_t *) cast);
+ branches = decl_branch_base(iseq, PTR2NUM(cast), &case_location, "case");
+ }
+
// Loop through each clauses in the case node and compile each of
// the conditions within them into cond_seq. If they match, they
// should jump into their respective bodies in body_seq.
@@ -4872,8 +5604,14 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
int clause_lineno = pm_node_line_number(parser, (const pm_node_t *) clause);
LABEL *label = NEW_LABEL(clause_lineno);
-
PUSH_LABEL(body_seq, label);
+
+ // Establish branch coverage for the when clause.
+ if (PM_BRANCH_COVERAGE_P(iseq)) {
+ rb_code_location_t branch_location = pm_code_location(scope_node, clause->statements != NULL ? ((const pm_node_t *) clause->statements) : ((const pm_node_t *) clause));
+ add_trace_branch_coverage(iseq, body_seq, &branch_location, branch_location.beg_pos.column, branch_id++, "when", branches);
+ }
+
if (clause->statements != NULL) {
pm_compile_node(iseq, (const pm_node_t *) clause->statements, body_seq, popped, scope_node);
}
@@ -4890,10 +5628,11 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
const pm_node_t *condition = conditions->nodes[condition_index];
if (PM_NODE_TYPE_P(condition, PM_SPLAT_NODE)) {
- PUSH_INSN(cond_seq, location, putnil);
+ pm_line_column_t cond_location = PM_NODE_START_LINE_COLUMN(parser, condition);
+ PUSH_INSN(cond_seq, cond_location, putnil);
pm_compile_node(iseq, condition, cond_seq, false, scope_node);
- PUSH_INSN1(cond_seq, location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
- PUSH_INSNL(cond_seq, location, branchif, label);
+ 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));
@@ -4903,12 +5642,28 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
}
}
+ // Establish branch coverage for the else clause (implicit or
+ // explicit).
+ if (PM_BRANCH_COVERAGE_P(iseq)) {
+ rb_code_location_t branch_location;
+
+ if (cast->consequent == NULL) {
+ branch_location = case_location;
+ } else if (cast->consequent->statements == NULL) {
+ branch_location = pm_code_location(scope_node, (const pm_node_t *) cast->consequent);
+ } else {
+ branch_location = pm_code_location(scope_node, (const pm_node_t *) cast->consequent->statements);
+ }
+
+ add_trace_branch_coverage(iseq, cond_seq, &branch_location, branch_location.beg_pos.column, branch_id, "else", branches);
+ }
+
// Compile the consequent else clause if there is one.
- if (cast->consequent) {
+ if (cast->consequent != NULL) {
pm_compile_node(iseq, (const pm_node_t *) cast->consequent, cond_seq, popped, scope_node);
}
else if (!popped) {
- PUSH_INSN(cond_seq, location, putnil);
+ PUSH_SYNTHETIC_PUTNIL(cond_seq, iseq);
}
// Finally, jump to the end label if none of the other conditions
@@ -4917,6 +5672,16 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_SEQ(ret, cond_seq);
}
else {
+ // Establish branch coverage for the case node.
+ VALUE branches = Qfalse;
+ rb_code_location_t case_location = { 0 };
+ int branch_id = 0;
+
+ if (PM_BRANCH_COVERAGE_P(iseq)) {
+ case_location = pm_code_location(scope_node, (const pm_node_t *) cast);
+ branches = decl_branch_base(iseq, PTR2NUM(cast), &case_location, "case");
+ }
+
// This is the label where everything will fall into if none of the
// conditions matched.
LABEL *else_label = NEW_LABEL(location.line);
@@ -4942,15 +5707,17 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// 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];
- const pm_node_list_t *conditions = &clause->conditions;
+ pm_line_column_t clause_location = PM_NODE_START_LINE_COLUMN(parser, (const pm_node_t *) clause);
- LABEL *label = NEW_LABEL(location.line);
+ const pm_node_list_t *conditions = &clause->conditions;
+ LABEL *label = NEW_LABEL(clause_location.line);
// Compile each of the conditions for the when clause into the
// cond_seq. Each one should have a unique comparison that then
// 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_line_column_t condition_location = PM_NODE_START_LINE_COLUMN(parser, condition);
// If we haven't already abandoned the optimization, then
// we're going to try to compile the condition into the
@@ -4960,25 +5727,25 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
}
if (PM_NODE_TYPE_P(condition, PM_SPLAT_NODE)) {
- PUSH_INSN(cond_seq, location, dup);
+ PUSH_INSN(cond_seq, condition_location, dup);
pm_compile_node(iseq, condition, cond_seq, false, scope_node);
- PUSH_INSN1(cond_seq, location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
+ PUSH_INSN1(cond_seq, condition_location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
}
else {
if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
const pm_string_node_t *string = (const pm_string_node_t *) condition;
VALUE value = parse_static_literal_string(iseq, scope_node, condition, &string->unescaped);
- PUSH_INSN1(cond_seq, location, putobject, value);
+ PUSH_INSN1(cond_seq, condition_location, putobject, value);
}
else {
pm_compile_node(iseq, condition, cond_seq, false, scope_node);
}
- PUSH_INSN1(cond_seq, location, topn, INT2FIX(1));
- PUSH_SEND_WITH_FLAG(cond_seq, location, idEqq, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
+ PUSH_INSN1(cond_seq, condition_location, topn, INT2FIX(1));
+ PUSH_SEND_WITH_FLAG(cond_seq, condition_location, idEqq, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
}
- PUSH_INSNL(cond_seq, location, branchif, label);
+ PUSH_INSNL(cond_seq, condition_location, branchif, label);
}
// Now, add the label to the body and compile the body of the
@@ -4986,16 +5753,22 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// the statements to be executed, and then compiling a jump to
// the end of the case node.
PUSH_LABEL(body_seq, label);
- PUSH_INSN(body_seq, location, pop);
+ PUSH_INSN(body_seq, clause_location, pop);
+
+ // Establish branch coverage for the when clause.
+ if (PM_BRANCH_COVERAGE_P(iseq)) {
+ rb_code_location_t branch_location = pm_code_location(scope_node, clause->statements != NULL ? ((const pm_node_t *) clause->statements) : ((const pm_node_t *) clause));
+ add_trace_branch_coverage(iseq, body_seq, &branch_location, branch_location.beg_pos.column, branch_id++, "when", branches);
+ }
if (clause->statements != NULL) {
pm_compile_node(iseq, (const pm_node_t *) clause->statements, body_seq, popped, scope_node);
}
else if (!popped) {
- PUSH_INSN(body_seq, location, putnil);
+ PUSH_INSN(body_seq, clause_location, putnil);
}
- PUSH_INSNL(body_seq, location, jump, end_label);
+ PUSH_INSNL(body_seq, clause_location, jump, end_label);
}
// Now that we have compiled the conditions and the bodies of the
@@ -5017,16 +5790,31 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// Compile either the explicit else clause or an implicit else
// clause.
PUSH_LABEL(ret, else_label);
- PUSH_INSN(ret, location, pop);
if (cast->consequent != NULL) {
+ pm_line_column_t else_location = PM_NODE_START_LINE_COLUMN(parser, cast->consequent->statements != NULL ? ((const pm_node_t *) cast->consequent->statements) : ((const pm_node_t *) cast->consequent));
+ PUSH_INSN(ret, else_location, pop);
+
+ // Establish branch coverage for the else clause.
+ if (PM_BRANCH_COVERAGE_P(iseq)) {
+ rb_code_location_t branch_location = pm_code_location(scope_node, cast->consequent->statements != NULL ? ((const pm_node_t *) cast->consequent->statements) : ((const pm_node_t *) cast->consequent));
+ add_trace_branch_coverage(iseq, ret, &branch_location, branch_location.beg_pos.column, branch_id, "else", branches);
+ }
+
PM_COMPILE((const pm_node_t *) cast->consequent);
+ PUSH_INSNL(ret, else_location, jump, end_label);
}
- else if (!popped) {
- PUSH_INSN(ret, location, putnil);
- }
+ else {
+ PUSH_INSN(ret, location, pop);
+
+ // Establish branch coverage for the implicit else clause.
+ if (PM_BRANCH_COVERAGE_P(iseq)) {
+ add_trace_branch_coverage(iseq, ret, &case_location, case_location.beg_pos.column, branch_id, "else", branches);
+ }
- PUSH_INSNL(ret, location, jump, end_label);
+ if (!popped) PUSH_INSN(ret, location, putnil);
+ PUSH_INSNL(ret, location, jump, end_label);
+ }
}
PUSH_SEQ(ret, body_seq);
@@ -5068,8 +5856,14 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// We're going to use this to uniquely identify each branch so that we
// can track coverage information.
+ rb_code_location_t case_location;
+ VALUE branches = Qfalse;
int branch_id = 0;
- // VALUE branches = 0;
+
+ if (PM_BRANCH_COVERAGE_P(iseq)) {
+ case_location = pm_code_location(scope_node, (const pm_node_t *) cast);
+ branches = decl_branch_base(iseq, PTR2NUM(cast), &case_location, "case");
+ }
// If there is only one pattern, then the behavior changes a bit. It
// effectively gets treated as a match required node (this is how it is
@@ -5109,12 +5903,12 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_LABEL(body_seq, body_label);
PUSH_INSN1(body_seq, in_location, adjuststack, INT2FIX(in_single_pattern ? 6 : 2));
- // TODO: We need to come back to this and enable trace branch
- // coverage. At the moment we can't call this function because it
- // accepts a NODE* and not a pm_node_t*.
- // add_trace_branch_coverage(iseq, body_seq, in_node->statements || in, branch_id++, "in", branches);
+ // Establish branch coverage for the in clause.
+ if (PM_BRANCH_COVERAGE_P(iseq)) {
+ rb_code_location_t branch_location = pm_code_location(scope_node, in_node->statements != NULL ? ((const pm_node_t *) in_node->statements) : ((const pm_node_t *) in_node));
+ add_trace_branch_coverage(iseq, body_seq, &branch_location, branch_location.beg_pos.column, branch_id++, "in", branches);
+ }
- branch_id++;
if (in_node->statements != NULL) {
PM_COMPILE_INTO_ANCHOR(body_seq, (const pm_node_t *) in_node->statements);
}
@@ -5141,16 +5935,13 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN(cond_seq, location, pop);
PUSH_INSN(cond_seq, location, pop);
- // TODO: trace branch coverage
- // add_trace_branch_coverage(iseq, cond_seq, cast->consequent, branch_id, "else", branches);
-
- if (else_node->statements != NULL) {
- PM_COMPILE_INTO_ANCHOR(cond_seq, (const pm_node_t *) else_node->statements);
- }
- else if (!popped) {
- PUSH_INSN(cond_seq, location, putnil);
+ // Establish branch coverage for the else clause.
+ if (PM_BRANCH_COVERAGE_P(iseq)) {
+ rb_code_location_t branch_location = pm_code_location(scope_node, else_node->statements != NULL ? ((const pm_node_t *) else_node->statements) : ((const pm_node_t *) else_node));
+ add_trace_branch_coverage(iseq, cond_seq, &branch_location, branch_location.beg_pos.column, branch_id, "else", branches);
}
+ PM_COMPILE_INTO_ANCHOR(cond_seq, (const pm_node_t *) else_node);
PUSH_INSNL(cond_seq, location, jump, end_label);
PUSH_INSN(cond_seq, location, putnil);
if (popped) PUSH_INSN(cond_seq, location, putnil);
@@ -5160,8 +5951,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// the code to handle raising an appropriate error.
PUSH_LABEL(cond_seq, else_label);
- // TODO: trace branch coverage
- // add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
+ // Establish branch coverage for the implicit else clause.
+ add_trace_branch_coverage(iseq, cond_seq, &case_location, case_location.beg_pos.column, branch_id, "else", branches);
if (in_single_pattern) {
pm_compile_pattern_error_handler(iseq, scope_node, node, cond_seq, end_label, popped);
@@ -5255,7 +6046,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN2(ret, location, getclassvariable, name, get_cvar_ic_value(iseq, name_id));
PM_COMPILE_NOT_POPPED(cast->value);
- ID method_id = pm_constant_id_lookup(scope_node, cast->operator);
+ ID method_id = pm_constant_id_lookup(scope_node, cast->binary_operator);
int flags = VM_CALL_ARGS_SIMPLE;
PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2NUM(1), INT2FIX(flags));
@@ -5349,154 +6140,28 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// Foo::Bar &&= baz
// ^^^^^^^^^^^^^^^^
const pm_constant_path_and_write_node_t *cast = (const pm_constant_path_and_write_node_t *) node;
- const pm_constant_path_node_t *target = cast->target;
-
- const pm_constant_read_node_t *child = (const pm_constant_read_node_t *) target->child;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, child->name));
- LABEL *lfin = NEW_LABEL(location.line);
-
- if (target->parent) {
- PM_COMPILE_NOT_POPPED(target->parent);
- }
- else {
- PUSH_INSN1(ret, location, putobject, rb_cObject);
- }
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putobject, Qtrue);
- PUSH_INSN1(ret, location, getconstant, name);
-
- if (!popped) PUSH_INSN(ret, location, dup);
- PUSH_INSNL(ret, location, branchunless, lfin);
-
- if (!popped) PUSH_INSN(ret, location, pop);
- PM_COMPILE_NOT_POPPED(cast->value);
-
- if (popped) {
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- }
- else {
- PUSH_INSN1(ret, location, dupn, INT2FIX(2));
- PUSH_INSN(ret, location, swap);
- }
-
- PUSH_INSN1(ret, location, setconstant, name);
- PUSH_LABEL(ret, lfin);
-
- if (!popped) PUSH_INSN(ret, location, swap);
- PUSH_INSN(ret, location, pop);
-
+ pm_compile_constant_path_and_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
return;
}
case PM_CONSTANT_PATH_OR_WRITE_NODE: {
// Foo::Bar ||= baz
// ^^^^^^^^^^^^^^^^
const pm_constant_path_or_write_node_t *cast = (const pm_constant_path_or_write_node_t *) node;
- const pm_constant_path_node_t *target = cast->target;
-
- const pm_constant_read_node_t *child = (const pm_constant_read_node_t *) target->child;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, child->name));
-
- LABEL *lassign = NEW_LABEL(location.line);
- LABEL *lfin = NEW_LABEL(location.line);
-
- if (target->parent) {
- PM_COMPILE_NOT_POPPED(target->parent);
- }
- else {
- PUSH_INSN1(ret, location, putobject, rb_cObject);
- }
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_CONST_FROM), name, Qtrue);
- PUSH_INSNL(ret, location, branchunless, lassign);
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putobject, Qtrue);
- PUSH_INSN1(ret, location, getconstant, name);
-
- if (!popped) PUSH_INSN(ret, location, dup);
- PUSH_INSNL(ret, location, branchif, lfin);
-
- if (!popped) PUSH_INSN(ret, location, pop);
- PUSH_LABEL(ret, lassign);
- PM_COMPILE_NOT_POPPED(cast->value);
-
- if (popped) {
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- }
- else {
- PUSH_INSN1(ret, location, dupn, INT2FIX(2));
- PUSH_INSN(ret, location, swap);
- }
-
- PUSH_INSN1(ret, location, setconstant, name);
- PUSH_LABEL(ret, lfin);
-
- if (!popped) PUSH_INSN(ret, location, swap);
- PUSH_INSN(ret, location, pop);
-
+ pm_compile_constant_path_or_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
return;
}
case PM_CONSTANT_PATH_OPERATOR_WRITE_NODE: {
// Foo::Bar += baz
// ^^^^^^^^^^^^^^^
const pm_constant_path_operator_write_node_t *cast = (const pm_constant_path_operator_write_node_t *) node;
- const pm_constant_path_node_t *target = cast->target;
- ID method_id = pm_constant_id_lookup(scope_node, cast->operator);
-
- const pm_constant_read_node_t *child = (const pm_constant_read_node_t *) target->child;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, child->name));
-
- if (target->parent) {
- PM_COMPILE_NOT_POPPED(target->parent);
- }
- else {
- PUSH_INSN1(ret, location, putobject, rb_cObject);
- }
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putobject, Qtrue);
- PUSH_INSN1(ret, location, getconstant, name);
-
- PM_COMPILE_NOT_POPPED(cast->value);
- PUSH_CALL(ret, location, method_id, INT2FIX(1));
- PUSH_INSN(ret, location, swap);
-
- if (!popped) {
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- PUSH_INSN(ret, location, swap);
- }
-
- PUSH_INSN1(ret, location, setconstant, name);
+ pm_compile_constant_path_operator_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
return;
}
case PM_CONSTANT_PATH_WRITE_NODE: {
// Foo::Bar = 1
// ^^^^^^^^^^^^
const pm_constant_path_write_node_t *cast = (const pm_constant_path_write_node_t *) node;
- const pm_constant_path_node_t *target = cast->target;
-
- const pm_constant_read_node_t *child = (const pm_constant_read_node_t *) target->child;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, child->name));
-
- if (target->parent) {
- PM_COMPILE_NOT_POPPED((const pm_node_t *) target->parent);
- }
- else {
- PUSH_INSN1(ret, location, putobject, rb_cObject);
- }
-
- PM_COMPILE_NOT_POPPED(cast->value);
-
- if (!popped) {
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- }
-
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, setconstant, name);
-
+ pm_compile_constant_path_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
return;
}
case PM_CONSTANT_READ_NODE: {
@@ -5514,82 +6179,28 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// Foo &&= bar
// ^^^^^^^^^^^
const pm_constant_and_write_node_t *cast = (const pm_constant_and_write_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
- LABEL *end_label = NEW_LABEL(location.line);
-
- pm_compile_constant_read(iseq, name, &cast->name_loc, ret, scope_node);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSNL(ret, location, branchunless, end_label);
- if (!popped) PUSH_INSN(ret, location, pop);
-
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- PUSH_INSN1(ret, location, setconstant, name);
- PUSH_LABEL(ret, end_label);
-
+ pm_compile_constant_and_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
return;
}
case PM_CONSTANT_OR_WRITE_NODE: {
// Foo ||= bar
// ^^^^^^^^^^^
const pm_constant_or_write_node_t *cast = (const pm_constant_or_write_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
- LABEL *set_label = NEW_LABEL(location.line);
- LABEL *end_label = NEW_LABEL(location.line);
-
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_CONST), name, Qtrue);
- PUSH_INSNL(ret, location, branchunless, set_label);
-
- pm_compile_constant_read(iseq, name, &cast->name_loc, ret, scope_node);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSNL(ret, location, branchif, end_label);
- if (!popped) PUSH_INSN(ret, location, pop);
-
- PUSH_LABEL(ret, set_label);
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- PUSH_INSN1(ret, location, setconstant, name);
- PUSH_LABEL(ret, end_label);
-
+ pm_compile_constant_or_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
return;
}
case PM_CONSTANT_OPERATOR_WRITE_NODE: {
// Foo += bar
// ^^^^^^^^^^
const pm_constant_operator_write_node_t *cast = (const pm_constant_operator_write_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
- ID method_id = pm_constant_id_lookup(scope_node, cast->operator);
-
- pm_compile_constant_read(iseq, name, &cast->name_loc, ret, scope_node);
- PM_COMPILE_NOT_POPPED(cast->value);
-
- PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2NUM(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- PUSH_INSN1(ret, location, setconstant, name);
-
+ pm_compile_constant_operator_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
return;
}
case PM_CONSTANT_WRITE_NODE: {
// Foo = 1
// ^^^^^^^
const pm_constant_write_node_t *cast = (const pm_constant_write_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
-
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- PUSH_INSN1(ret, location, setconstant, name);
-
+ pm_compile_constant_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
return;
}
case PM_DEF_NODE: {
@@ -5686,7 +6297,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PM_COMPILE((const pm_node_t *) cast->statements);
}
else if (!popped) {
- PUSH_INSN(ret, location, putnil);
+ PUSH_SYNTHETIC_PUTNIL(ret, iseq);
}
return;
@@ -5745,33 +6356,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// Now, create the method call to each that will be used to iterate over
// the collection, and pass the newly created iseq as the block.
PUSH_SEND_WITH_BLOCK(ret, location, idEach, INT2FIX(0), child_iseq);
-
- // We need to put the label "retry_end_l" immediately after the last
- // "send" instruction. This because vm_throw checks if the break cont is
- // equal to the index of next insn of the "send". (Otherwise, it is
- // considered "break from proc-closure". See "TAG_BREAK" handling in
- // "vm_throw_start".)
- //
- // Normally, "send" instruction is at the last. However, qcall under
- // branch coverage measurement adds some instructions after the "send".
- //
- // Note that "invokesuper" appears instead of "send".
- {
- INSN *iobj;
- LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
- iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
- while (INSN_OF(iobj) != BIN(send) && INSN_OF(iobj) != BIN(invokesuper)) {
- iobj = (INSN*) get_prev_insn(iobj);
- }
- ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
-
- // LINK_ANCHOR has a pointer to the last element, but
- // ELEM_INSERT_NEXT does not update it even if we add an insn to the
- // last of LINK_ANCHOR. So this updates it manually.
- if (&iobj->link == LAST_ELEMENT(ret)) {
- ret->last = (LINK_ELEMENT*) retry_end_l;
- }
- }
+ pm_compile_retry_end_label(iseq, ret, retry_end_l);
if (popped) PUSH_INSN(ret, location, pop);
ISEQ_COMPILE_DATA(iseq)->current_block = prev_block;
@@ -5914,7 +6499,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN2(ret, location, invokesuper, new_callinfo(iseq, 0, argc, flag, NULL, block != NULL), block);
if (cast->block != NULL) {
- PUSH_LABEL(ret, retry_end_l);
+ pm_compile_retry_end_label(iseq, ret, retry_end_l);
PUSH_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, block, retry_end_l);
ISEQ_COMPILE_DATA(iseq)->current_block = previous_block;
}
@@ -5952,7 +6537,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN1(ret, location, getglobal, name);
PM_COMPILE_NOT_POPPED(cast->value);
- ID method_id = pm_constant_id_lookup(scope_node, cast->operator);
+ ID method_id = pm_constant_id_lookup(scope_node, cast->binary_operator);
int flags = VM_CALL_ARGS_SIMPLE;
PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2NUM(1), INT2FIX(flags));
@@ -6065,7 +6650,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// foo ? bar : baz
// ^^^^^^^^^^^^^^^
const pm_if_node_t *cast = (const pm_if_node_t *) node;
- pm_compile_conditional(iseq, &location, cast->statements, cast->consequent, cast->predicate, ret, popped, scope_node);
+ pm_compile_conditional(iseq, &location, PM_IF_NODE, (const pm_node_t *) cast, cast->statements, cast->consequent, cast->predicate, ret, popped, scope_node);
return;
}
case PM_IMAGINARY_NODE: {
@@ -6150,7 +6735,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN2(ret, location, getinstancevariable, name, get_ivar_ic_value(iseq, name_id));
PM_COMPILE_NOT_POPPED(cast->value);
- ID method_id = pm_constant_id_lookup(scope_node, cast->operator);
+ ID method_id = pm_constant_id_lookup(scope_node, cast->binary_operator);
int flags = VM_CALL_ARGS_SIMPLE;
PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2NUM(1), INT2FIX(flags));
@@ -6286,7 +6871,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
}
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);
+ int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL);
if (length > 1) PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
if (popped) PUSH_INSN(ret, location, pop);
}
@@ -6305,7 +6890,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
}
}
else {
- int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node);
+ int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL);
if (length > 1) {
PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
}
@@ -6327,7 +6912,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);
+ int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, false, scope_node, NULL, NULL);
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));
@@ -6400,7 +6985,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PM_COMPILE_NOT_POPPED(cast->value);
- ID method_id = pm_constant_id_lookup(scope_node, cast->operator);
+ ID method_id = pm_constant_id_lookup(scope_node, cast->binary_operator);
PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2NUM(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
if (!popped) PUSH_INSN(ret, location, dup);
@@ -7205,53 +7790,63 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
const pm_return_node_t *cast = (const pm_return_node_t *) node;
const pm_arguments_node_t *arguments = cast->arguments;
- enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
- LABEL *splabel = 0;
-
- const rb_iseq_t *parent_iseq = iseq;
- enum rb_iseq_type parent_type = ISEQ_BODY(parent_iseq)->type;
- while (parent_type == ISEQ_TYPE_RESCUE || parent_type == ISEQ_TYPE_ENSURE) {
- if (!(parent_iseq = ISEQ_BODY(parent_iseq)->parent_iseq)) break;
- parent_type = ISEQ_BODY(parent_iseq)->type;
- }
-
- switch (parent_type) {
- case ISEQ_TYPE_TOP:
- case ISEQ_TYPE_MAIN:
+ if (PM_NODE_FLAG_P(cast, PM_RETURN_NODE_FLAGS_REDUNDANT)) {
if (arguments) {
- rb_warn("argument of top-level return is ignored");
+ PM_COMPILE_NOT_POPPED((const pm_node_t *) arguments);
}
- if (parent_iseq == iseq) {
- type = ISEQ_TYPE_METHOD;
+ else {
+ PUSH_INSN(ret, location, putnil);
}
- break;
- default:
- break;
}
+ else {
+ enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
+ LABEL *splabel = 0;
- if (type == ISEQ_TYPE_METHOD) {
- splabel = NEW_LABEL(0);
- PUSH_LABEL(ret, splabel);
- PUSH_ADJUST(ret, location, 0);
- }
+ const rb_iseq_t *parent_iseq = iseq;
+ enum rb_iseq_type parent_type = ISEQ_BODY(parent_iseq)->type;
+ while (parent_type == ISEQ_TYPE_RESCUE || parent_type == ISEQ_TYPE_ENSURE) {
+ if (!(parent_iseq = ISEQ_BODY(parent_iseq)->parent_iseq)) break;
+ parent_type = ISEQ_BODY(parent_iseq)->type;
+ }
- if (arguments) {
- PM_COMPILE_NOT_POPPED((const pm_node_t *) arguments);
- }
- else {
- PUSH_INSN(ret, location, putnil);
- }
+ switch (parent_type) {
+ case ISEQ_TYPE_TOP:
+ case ISEQ_TYPE_MAIN:
+ if (arguments) {
+ rb_warn("argument of top-level return is ignored");
+ }
+ if (parent_iseq == iseq) {
+ type = ISEQ_TYPE_METHOD;
+ }
+ break;
+ default:
+ break;
+ }
- if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
- pm_add_ensure_iseq(ret, iseq, 1, scope_node);
- PUSH_TRACE(ret, RUBY_EVENT_RETURN);
- PUSH_INSN(ret, location, leave);
- PUSH_ADJUST_RESTORE(ret, splabel);
- if (!popped) PUSH_INSN(ret, location, putnil);
- }
- else {
- PUSH_INSN1(ret, location, throw, INT2FIX(TAG_RETURN));
- if (popped) PUSH_INSN(ret, location, pop);
+ if (type == ISEQ_TYPE_METHOD) {
+ splabel = NEW_LABEL(0);
+ PUSH_LABEL(ret, splabel);
+ PUSH_ADJUST(ret, location, 0);
+ }
+
+ if (arguments) {
+ PM_COMPILE_NOT_POPPED((const pm_node_t *) arguments);
+ }
+ else {
+ PUSH_INSN(ret, location, putnil);
+ }
+
+ if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
+ pm_add_ensure_iseq(ret, iseq, 1, scope_node);
+ PUSH_TRACE(ret, RUBY_EVENT_RETURN);
+ PUSH_INSN(ret, location, leave);
+ PUSH_ADJUST_RESTORE(ret, splabel);
+ if (!popped) PUSH_INSN(ret, location, putnil);
+ }
+ else {
+ PUSH_INSN1(ret, location, throw, INT2FIX(TAG_RETURN));
+ if (popped) PUSH_INSN(ret, location, pop);
+ }
}
return;
@@ -8150,7 +8745,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
break;
}
- if (PM_NODE_TYPE_P(scope_node->ast_node, PM_CLASS_NODE)) {
+ 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_line_column_t end_location = PM_NODE_END_LINE_COLUMN(scope_node->parser, scope_node->ast_node);
ADD_TRACE(ret, RUBY_EVENT_END);
ISEQ_COMPILE_DATA(iseq)->last_line = end_location.line;
@@ -8174,7 +8769,38 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
case PM_SHAREABLE_CONSTANT_NODE: {
// A value that is being written to a constant that is being marked as
// shared depending on the current lexical context.
- PM_COMPILE(((const pm_shareable_constant_node_t *) node)->write);
+ const pm_shareable_constant_node_t *cast = (const pm_shareable_constant_node_t *) node;
+
+ switch (PM_NODE_TYPE(cast->write)) {
+ case PM_CONSTANT_WRITE_NODE:
+ pm_compile_constant_write_node(iseq, (const pm_constant_write_node_t *) cast->write, cast->base.flags, &location, ret, popped, scope_node);
+ break;
+ case PM_CONSTANT_AND_WRITE_NODE:
+ pm_compile_constant_and_write_node(iseq, (const pm_constant_and_write_node_t *) cast->write, cast->base.flags, &location, ret, popped, scope_node);
+ break;
+ case PM_CONSTANT_OR_WRITE_NODE:
+ pm_compile_constant_or_write_node(iseq, (const pm_constant_or_write_node_t *) cast->write, cast->base.flags, &location, ret, popped, scope_node);
+ break;
+ case PM_CONSTANT_OPERATOR_WRITE_NODE:
+ pm_compile_constant_operator_write_node(iseq, (const pm_constant_operator_write_node_t *) cast->write, cast->base.flags, &location, ret, popped, scope_node);
+ break;
+ case PM_CONSTANT_PATH_WRITE_NODE:
+ pm_compile_constant_path_write_node(iseq, (const pm_constant_path_write_node_t *) cast->write, cast->base.flags, &location, ret, popped, scope_node);
+ break;
+ case PM_CONSTANT_PATH_AND_WRITE_NODE:
+ pm_compile_constant_path_and_write_node(iseq, (const pm_constant_path_and_write_node_t *) cast->write, cast->base.flags, &location, ret, popped, scope_node);
+ break;
+ case PM_CONSTANT_PATH_OR_WRITE_NODE:
+ pm_compile_constant_path_or_write_node(iseq, (const pm_constant_path_or_write_node_t *) cast->write, cast->base.flags, &location, ret, popped, scope_node);
+ break;
+ case PM_CONSTANT_PATH_OPERATOR_WRITE_NODE:
+ pm_compile_constant_path_operator_write_node(iseq, (const pm_constant_path_operator_write_node_t *) cast->write, cast->base.flags, &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)));
+ break;
+ }
+
return;
}
case PM_SINGLETON_CLASS_NODE: {
@@ -8321,9 +8947,9 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_SEQ(ret, args);
PUSH_INSN2(ret, location, invokesuper, new_callinfo(iseq, 0, argc, flags, keywords, current_block != NULL), current_block);
- PUSH_LABEL(ret, retry_end_l);
- if (popped) PUSH_INSN(ret, location, pop);
+ pm_compile_retry_end_label(iseq, ret, retry_end_l);
+ if (popped) PUSH_INSN(ret, location, pop);
ISEQ_COMPILE_DATA(iseq)->current_block = previous_block;
PUSH_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, current_block, retry_end_l);
@@ -8379,7 +9005,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
consequent = ((const pm_else_node_t *) cast->consequent)->statements;
}
- pm_compile_conditional(iseq, &location, consequent, (const pm_node_t *) cast->statements, cast->predicate, ret, popped, scope_node);
+ pm_compile_conditional(iseq, &location, PM_UNLESS_NODE, (const pm_node_t *) cast, consequent, (const pm_node_t *) cast->statements, cast->predicate, ret, popped, scope_node);
return;
}
case PM_UNTIL_NODE: {
@@ -8389,7 +9015,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// bar until foo
// ^^^^^^^^^^^^^
const pm_until_node_t *cast = (const pm_until_node_t *) node;
- pm_compile_loop(iseq, &location, cast->base.flags, PM_UNTIL_NODE, cast->statements, cast->predicate, ret, popped, scope_node);
+ pm_compile_loop(iseq, &location, cast->base.flags, PM_UNTIL_NODE, (const pm_node_t *) cast, cast->statements, cast->predicate, ret, popped, scope_node);
return;
}
case PM_WHILE_NODE: {
@@ -8399,7 +9025,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// bar while foo
// ^^^^^^^^^^^^^
const pm_while_node_t *cast = (const pm_while_node_t *) node;
- pm_compile_loop(iseq, &location, cast->base.flags, PM_WHILE_NODE, cast->statements, cast->predicate, ret, popped, scope_node);
+ pm_compile_loop(iseq, &location, cast->base.flags, PM_WHILE_NODE, (const pm_node_t *) cast, cast->statements, cast->predicate, ret, popped, scope_node);
return;
}
case PM_X_STRING_NODE: {
@@ -8643,7 +9269,8 @@ pm_parse_process_error(const pm_parse_result_t *result)
}
}
- VALUE error = rb_exc_new(rb_eSyntaxError, pm_buffer_value(&buffer), pm_buffer_length(&buffer));
+ 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_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);
@@ -8654,6 +9281,9 @@ pm_parse_process_error(const pm_parse_result_t *result)
return error;
}
+void rb_enc_compile_warning(rb_encoding *enc, const char *file, int line, const char *fmt, ...);
+void rb_enc_compile_warn(rb_encoding *enc, const char *file, int line, const char *fmt, ...);
+
/**
* 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
@@ -8672,6 +9302,9 @@ pm_parse_process(pm_parse_result_t *result, pm_node_t *node)
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);
+
// 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);
@@ -8680,10 +9313,10 @@ pm_parse_process(pm_parse_result_t *result, pm_node_t *node)
int line = pm_location_line_number(parser, &warning->location);
if (warning->level == PM_WARNING_LEVEL_VERBOSE) {
- rb_compile_warning(warning_filepath, line, "%s", warning->message);
+ rb_enc_compile_warning(scope_node->encoding, warning_filepath, line, "%s", warning->message);
}
else {
- rb_compile_warn(warning_filepath, line, "%s", warning->message);
+ rb_enc_compile_warn(scope_node->encoding, warning_filepath, line, "%s", warning->message);
}
}
@@ -8698,9 +9331,6 @@ pm_parse_process(pm_parse_result_t *result, pm_node_t *node)
// Now set up the constant pool and intern all of the various constants into
// their corresponding IDs.
- scope_node->encoding = rb_enc_find(parser->encoding->name);
- if (!scope_node->encoding) rb_bug("Encoding not found %s!", parser->encoding->name);
-
scope_node->parser = parser;
scope_node->constants = calloc(parser->constant_pool.size, sizeof(ID));
@@ -8785,7 +9415,7 @@ pm_parse_file_script_lines(const pm_scope_node_t *scope_node, const pm_parser_t
* be read.
*/
VALUE
-pm_load_file(pm_parse_result_t *result, VALUE filepath)
+pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error)
{
if (!pm_string_mapped_init(&result->input, RSTRING_PTR(filepath))) {
#ifdef _WIN32
@@ -8794,9 +9424,21 @@ pm_load_file(pm_parse_result_t *result, VALUE filepath)
int e = errno;
#endif
- VALUE err = rb_syserr_new(e, RSTRING_PTR(filepath));
- RB_GC_GUARD(filepath);
- return err;
+ VALUE error;
+
+ if (load_error) {
+ VALUE message = rb_str_buf_new_cstr(strerror(e));
+ rb_str_cat2(message, " -- ");
+ rb_str_append(message, filepath);
+
+ error = rb_exc_new3(rb_eLoadError, message);
+ rb_ivar_set(error, rb_intern_const("@path"), filepath);
+ } else {
+ error = rb_syserr_new(e, RSTRING_PTR(filepath));
+ RB_GC_GUARD(filepath);
+ }
+
+ return error;
}
pm_options_frozen_string_literal_init(&result->options);
@@ -8843,7 +9485,7 @@ pm_parse_file(pm_parse_result_t *result, VALUE filepath)
VALUE
pm_load_parse_file(pm_parse_result_t *result, VALUE filepath)
{
- VALUE error = pm_load_file(result, filepath);
+ VALUE error = pm_load_file(result, filepath, false);
if (NIL_P(error)) {
error = pm_parse_file(result, filepath);
}
diff --git a/prism_compile.h b/prism_compile.h
index e58bed271f..0f82782ec0 100644
--- a/prism_compile.h
+++ b/prism_compile.h
@@ -72,7 +72,7 @@ typedef struct {
bool parsed;
} pm_parse_result_t;
-VALUE pm_load_file(pm_parse_result_t *result, VALUE filepath);
+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 pm_load_parse_file(pm_parse_result_t *result, VALUE filepath);
VALUE pm_parse_string(pm_parse_result_t *result, VALUE source, VALUE filepath);
diff --git a/proc.c b/proc.c
index bfde0d9abb..1a67a63663 100644
--- a/proc.c
+++ b/proc.c
@@ -3467,7 +3467,7 @@ proc_binding(VALUE self)
env = VM_ENV_ENVVAL_PTR(block->as.captured.ep);
env = env_clone(env, method_cref(method));
/* set empty iseq */
- empty = rb_iseq_new(NULL, name, name, Qnil, 0, ISEQ_TYPE_TOP);
+ empty = rb_iseq_new(Qnil, name, name, Qnil, 0, ISEQ_TYPE_TOP);
RB_OBJ_WRITE(env, &env->iseq, empty);
break;
}
diff --git a/ractor.c b/ractor.c
index 7b9c088ceb..231a83db6f 100644
--- a/ractor.c
+++ b/ractor.c
@@ -1804,17 +1804,17 @@ ractor_select_internal(rb_execution_context_t *ec, VALUE self, VALUE ractors, VA
int state;
EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG() == TAG_NONE)) {
+ if ((state = EC_EXEC_TAG()) == TAG_NONE) {
result = ractor_selector__wait(selector, do_receive, do_yield, yield_value, move);
}
- else {
+ EC_POP_TAG();
+ if (state != TAG_NONE) {
// ensure
ractor_selector_clear(selector);
// jump
EC_JUMP_TAG(ec, state);
}
- EC_POP_TAG();
RB_GC_GUARD(ractors);
return result;
@@ -2012,12 +2012,11 @@ ractor_alloc(VALUE klass)
rb_ractor_t *
rb_ractor_main_alloc(void)
{
- rb_ractor_t *r = ruby_mimmalloc(sizeof(rb_ractor_t));
+ 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);
}
- MEMZERO(r, rb_ractor_t, 1);
r->pub.id = ++ractor_last_id;
r->loc = Qnil;
r->name = Qnil;
diff --git a/re.c b/re.c
index 9c47449271..c8940ff887 100644
--- a/re.c
+++ b/re.c
@@ -1530,8 +1530,8 @@ reg_enc_error(VALUE re, VALUE str)
{
rb_raise(rb_eEncCompatError,
"incompatible encoding regexp match (%s regexp with %s string)",
- rb_enc_name(rb_enc_get(re)),
- rb_enc_name(rb_enc_get(str)));
+ rb_enc_inspect_name(rb_enc_get(re)),
+ rb_enc_inspect_name(rb_enc_get(str)));
}
static inline int
diff --git a/regexec.c b/regexec.c
index 9533291584..6d82429e03 100644
--- a/regexec.c
+++ b/regexec.c
@@ -3449,8 +3449,8 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_MEMORY_END_PUSH_REC) MOP_IN(OP_MEMORY_END_PUSH_REC);
GET_MEMNUM_INC(mem, p);
STACK_GET_MEM_START(mem, stkp); /* should be before push mem-end. */
- STACK_PUSH_MEM_END(mem, s);
mem_start_stk[mem] = GET_STACK_INDEX(stkp);
+ STACK_PUSH_MEM_END(mem, s);
MOP_OUT;
JUMP;
@@ -4218,7 +4218,8 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
timeout:
xfree(xmalloc_base);
- xfree(stk_base);
+ if (stk_base != stk_alloc || IS_NOT_NULL(msa->stack_p))
+ xfree(stk_base);
HANDLE_REG_TIMEOUT_IN_MATCH_AT;
}
@@ -4920,12 +4921,17 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s,
UChar* range, UChar** low, UChar** high, UChar** low_prev)
{
UChar *p, *pprev = (UChar* )NULL;
+ size_t input_len = end - str;
#ifdef ONIG_DEBUG_SEARCH
fprintf(stderr, "forward_search_range: str: %"PRIuPTR" (%p), end: %"PRIuPTR" (%p), s: %"PRIuPTR" (%p), range: %"PRIuPTR" (%p)\n",
(uintptr_t )str, str, (uintptr_t )end, end, (uintptr_t )s, s, (uintptr_t )range, range);
#endif
+ if (reg->dmin > input_len) {
+ return 0;
+ }
+
p = s;
if (reg->dmin > 0) {
if (ONIGENC_IS_SINGLEBYTE(reg->enc)) {
@@ -5062,6 +5068,11 @@ backward_search_range(regex_t* reg, const UChar* str, const UChar* end,
UChar** low, UChar** high)
{
UChar *p;
+ size_t input_len = end - str;
+
+ if (reg->dmin > input_len) {
+ return 0;
+ }
range += reg->dmin;
p = s;
diff --git a/ruby.c b/ruby.c
index e939320f1f..cd7f9ad4b8 100644
--- a/ruby.c
+++ b/ruby.c
@@ -225,7 +225,7 @@ cmdline_options_init(ruby_cmdline_options_t *opt)
return opt;
}
-static rb_ast_t *load_file(VALUE parser, VALUE fname, VALUE f, int script,
+static VALUE load_file(VALUE parser, VALUE fname, VALUE f, int script,
ruby_cmdline_options_t *opt);
static VALUE open_load_file(VALUE fname_v, int *xflag);
static void forbid_setid(const char *, const ruby_cmdline_options_t *);
@@ -2056,10 +2056,11 @@ show_help(const char *progname, int help)
usage(progname, help, tty, columns);
}
-static rb_ast_t *
+static VALUE
process_script(ruby_cmdline_options_t *opt)
{
rb_ast_t *ast;
+ VALUE ast_value;
VALUE parser = rb_parser_new();
const unsigned int dump = opt->dump;
@@ -2079,7 +2080,7 @@ process_script(ruby_cmdline_options_t *opt)
ruby_set_script_name(progname);
rb_parser_set_options(parser, opt->do_print, opt->do_loop,
opt->do_line, opt->do_split);
- ast = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
+ ast_value = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
}
else {
VALUE f;
@@ -2087,13 +2088,14 @@ process_script(ruby_cmdline_options_t *opt)
f = open_load_file(opt->script_name, &xflag);
opt->xflag = xflag != 0;
rb_parser_set_context(parser, 0, f == rb_stdin);
- ast = load_file(parser, opt->script_name, f, 1, opt);
+ ast_value = load_file(parser, opt->script_name, f, 1, opt);
}
+ ast = rb_ruby_ast_data_get(ast_value);
if (!ast->body.root) {
rb_ast_dispose(ast);
- return NULL;
+ return Qnil;
}
- return ast;
+ return ast_value;
}
/**
@@ -2157,7 +2159,7 @@ prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result)
}
else {
pm_options_command_line_set(options, command_line);
- error = pm_load_file(result, opt->script_name);
+ error = pm_load_file(result, opt->script_name, true);
// If reading the file did not error, at that point we load the command
// line options. We do it in this order so that if the main script fails
@@ -2237,6 +2239,7 @@ process_options_global_setup(const ruby_cmdline_options_t *opt, const rb_iseq_t
static VALUE
process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
{
+ VALUE ast_value = Qnil;
struct {
rb_ast_t *ast;
pm_parse_result_t prism;
@@ -2471,7 +2474,8 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
}
if (!(*rb_ruby_prism_ptr())) {
- if (!(result.ast = process_script(opt))) return Qfalse;
+ ast_value = process_script(opt);
+ if (!(result.ast = rb_ruby_ast_data_get(ast_value))) return Qfalse;
}
else {
prism_script(opt, &result.prism);
@@ -2553,7 +2557,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
}
else {
rb_ast_t *ast = result.ast;
- iseq = rb_iseq_new_main(&ast->body, opt->script_name, path, parent, optimize);
+ iseq = rb_iseq_new_main(ast_value, opt->script_name, path, parent, optimize);
rb_ast_dispose(ast);
}
}
@@ -2604,7 +2608,7 @@ load_file_internal(VALUE argp_v)
ruby_cmdline_options_t *opt = argp->opt;
VALUE f = argp->f;
int line_start = 1;
- rb_ast_t *ast = 0;
+ VALUE ast_value = Qnil;
rb_encoding *enc;
ID set_encoding;
@@ -2702,10 +2706,10 @@ load_file_internal(VALUE argp_v)
if (NIL_P(f)) {
f = rb_str_new(0, 0);
rb_enc_associate(f, enc);
- return (VALUE)rb_parser_compile_string_path(parser, orig_fname, f, line_start);
+ return rb_parser_compile_string_path(parser, orig_fname, f, line_start);
}
rb_funcall(f, set_encoding, 2, rb_enc_from_encoding(enc), rb_str_new_cstr("-"));
- ast = rb_parser_compile_file_path(parser, orig_fname, f, line_start);
+ ast_value = rb_parser_compile_file_path(parser, orig_fname, f, line_start);
rb_funcall(f, set_encoding, 1, rb_parser_encoding(parser));
if (script && rb_parser_end_seen_p(parser)) {
/*
@@ -2723,7 +2727,7 @@ load_file_internal(VALUE argp_v)
rb_define_global_const("DATA", f);
argp->f = Qnil;
}
- return (VALUE)ast;
+ return ast_value;
}
/* disabling O_NONBLOCK, and returns 0 on success, otherwise errno */
@@ -2832,7 +2836,7 @@ restore_load_file(VALUE arg)
return Qnil;
}
-static rb_ast_t *
+static VALUE
load_file(VALUE parser, VALUE fname, VALUE f, int script, ruby_cmdline_options_t *opt)
{
struct load_file_arg arg;
@@ -2841,7 +2845,7 @@ load_file(VALUE parser, VALUE fname, VALUE f, int script, ruby_cmdline_options_t
arg.script = script;
arg.opt = opt;
arg.f = f;
- return (rb_ast_t *)rb_ensure(load_file_internal, (VALUE)&arg,
+ return rb_ensure(load_file_internal, (VALUE)&arg,
restore_load_file, (VALUE)&arg);
}
@@ -2855,10 +2859,12 @@ rb_load_file(const char *fname)
void *
rb_load_file_str(VALUE fname_v)
{
- return rb_parser_load_file(rb_parser_new(), fname_v);
+ VALUE ast_value;
+ ast_value = rb_parser_load_file(rb_parser_new(), fname_v);
+ return (void *)rb_ruby_ast_data_get(ast_value);
}
-void *
+VALUE
rb_parser_load_file(VALUE parser, VALUE fname_v)
{
ruby_cmdline_options_t opt;
diff --git a/ruby_parser.c b/ruby_parser.c
index 16a868bc6b..1dcdfd8e79 100644
--- a/ruby_parser.c
+++ b/ruby_parser.c
@@ -1,5 +1,6 @@
/* This is a wrapper for parse.y */
+#include "internal/parse.h"
#include "internal/re.h"
#include "internal/ruby_parser.h"
@@ -18,7 +19,6 @@
#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/io.h"
-#include "internal/parse.h"
#include "internal/rational.h"
#include "internal/re.h"
#include "internal/string.h"
@@ -32,40 +32,7 @@
#include "vm_core.h"
#include "symbol.h"
-struct ruby_parser {
- rb_parser_t *parser_params;
-};
-
-static void
-parser_mark(void *ptr)
-{
- struct ruby_parser *parser = (struct ruby_parser*)ptr;
- rb_ruby_parser_mark(parser->parser_params);
-}
-
-static void
-parser_free(void *ptr)
-{
- struct ruby_parser *parser = (struct ruby_parser*)ptr;
- rb_ruby_parser_free(parser->parser_params);
-}
-
-static size_t
-parser_memsize(const void *ptr)
-{
- struct ruby_parser *parser = (struct ruby_parser*)ptr;
- return rb_ruby_parser_memsize(parser->parser_params);
-}
-
-static const rb_data_type_t ruby_parser_data_type = {
- "parser",
- {
- parser_mark,
- parser_free,
- parser_memsize,
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
-};
+#define parser_encoding const void
static int
is_ascii_string2(VALUE str)
@@ -76,9 +43,9 @@ is_ascii_string2(VALUE str)
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 6, 0)
static VALUE
syntax_error_append(VALUE exc, VALUE file, int line, int column,
- void *enc, const char *fmt, va_list args)
+ parser_encoding *enc, const char *fmt, va_list args)
{
- return rb_syntax_error_append(exc, file, line, column, (rb_encoding *)enc, fmt, args);
+ return rb_syntax_error_append(exc, file, line, column, enc, fmt, args);
}
static int
@@ -94,9 +61,9 @@ dvar_defined(ID id, const void *p)
}
static int
-is_usascii_enc(void *enc)
+is_usascii_enc(parser_encoding *enc)
{
- return rb_is_usascii_enc((rb_encoding *)enc);
+ return rb_is_usascii_enc(enc);
}
static int
@@ -118,21 +85,21 @@ is_notop_id2(ID id)
}
static VALUE
-enc_str_new(const char *ptr, long len, void *enc)
+enc_str_new(const char *ptr, long len, parser_encoding *enc)
{
- return rb_enc_str_new(ptr, len, (rb_encoding *)enc);
+ return rb_enc_str_new(ptr, len, enc);
}
static int
-enc_isalnum(OnigCodePoint c, void *enc)
+enc_isalnum(OnigCodePoint c, parser_encoding *enc)
{
- return rb_enc_isalnum(c, (rb_encoding *)enc);
+ return rb_enc_isalnum(c, enc);
}
static int
-enc_precise_mbclen(const char *p, const char *e, void *enc)
+enc_precise_mbclen(const char *p, const char *e, parser_encoding *enc)
{
- return rb_enc_precise_mbclen(p, e, (rb_encoding *)enc);
+ return rb_enc_precise_mbclen(p, e, enc);
}
static int
@@ -148,105 +115,93 @@ mbclen_charfound_len(int len)
}
static const char *
-enc_name(void *enc)
+enc_name(parser_encoding *enc)
{
- return rb_enc_name((rb_encoding *)enc);
+ return rb_enc_name(enc);
}
static char *
-enc_prev_char(const char *s, const char *p, const char *e, void *enc)
+enc_prev_char(const char *s, const char *p, const char *e, parser_encoding *enc)
{
- return rb_enc_prev_char(s, p, e, (rb_encoding *)enc);
+ return rb_enc_prev_char(s, p, e, enc);
}
-static void *
+static parser_encoding *
enc_get(VALUE obj)
{
- return (void *)rb_enc_get(obj);
+ return rb_enc_get(obj);
}
static int
-enc_asciicompat(void *enc)
+enc_asciicompat(parser_encoding *enc)
{
- return rb_enc_asciicompat((rb_encoding *)enc);
+ return rb_enc_asciicompat(enc);
}
-static void *
+static parser_encoding *
utf8_encoding(void)
{
- return (void *)rb_utf8_encoding();
+ return rb_utf8_encoding();
}
static VALUE
-enc_associate(VALUE obj, void *enc)
+enc_associate(VALUE obj, parser_encoding *enc)
{
- return rb_enc_associate(obj, (rb_encoding *)enc);
+ return rb_enc_associate(obj, enc);
}
-static void *
+static parser_encoding *
ascii8bit_encoding(void)
{
- return (void *)rb_ascii8bit_encoding();
+ return rb_ascii8bit_encoding();
}
static int
-enc_codelen(int c, void *enc)
+enc_codelen(int c, parser_encoding *enc)
{
- return rb_enc_codelen(c, (rb_encoding *)enc);
+ return rb_enc_codelen(c, enc);
}
static int
-enc_mbcput(unsigned int c, void *buf, void *enc)
-{
- return rb_enc_mbcput(c, buf, (rb_encoding *)enc);
-}
-
-static void *
-enc_from_index(int idx)
+enc_mbcput(unsigned int c, void *buf, parser_encoding *enc)
{
- return (void *)rb_enc_from_index(idx);
+ return rb_enc_mbcput(c, buf, enc);
}
static int
-enc_isspace(OnigCodePoint c, void *enc)
+enc_mbclen(const char *p, const char *e, parser_encoding *enc)
{
- return rb_enc_isspace(c, (rb_encoding *)enc);
+ return rb_enc_mbclen(p, e, enc);
}
-static ID
-intern3(const char *name, long len, void *enc)
-{
- return rb_intern3(name, len, (rb_encoding *)enc);
-}
-
-static void *
-enc_compatible(VALUE str1, VALUE str2)
+static parser_encoding *
+enc_from_index(int idx)
{
- return (void *)rb_enc_compatible(str1, str2);
+ return rb_enc_from_index(idx);
}
-static VALUE
-enc_from_encoding(void *enc)
+static int
+enc_isspace(OnigCodePoint c, parser_encoding *enc)
{
- return rb_enc_from_encoding((rb_encoding *)enc);
+ return rb_enc_isspace(c, enc);
}
-static int
-encoding_is_ascii8bit(VALUE obj)
+static ID
+intern3(const char *name, long len, parser_encoding *enc)
{
- return ENCODING_IS_ASCII8BIT(obj);
+ return rb_intern3(name, len, enc);
}
-static void *
+static parser_encoding *
usascii_encoding(void)
{
- return (void *)rb_usascii_encoding();
+ return rb_usascii_encoding();
}
static int
-enc_symname_type(const char *name, long len, void *enc, unsigned int allowed_attrset)
+enc_symname_type(const char *name, long len, parser_encoding *enc, unsigned int allowed_attrset)
{
- return rb_enc_symname_type(name, len, (rb_encoding *)enc, allowed_attrset);
+ return rb_enc_symname_type(name, len, enc, allowed_attrset);
}
typedef struct {
@@ -267,7 +222,7 @@ reg_named_capture_assign_iter(const OnigUChar *name, const OnigUChar *name_end,
long len = name_end - name;
const char *s = (const char *)name;
- return rb_reg_named_capture_assign_iter_impl(p, s, len, (void *)enc, &arg->succ_block, loc);
+ return rb_reg_named_capture_assign_iter_impl(p, s, len, enc, &arg->succ_block, loc);
}
static NODE *
@@ -285,12 +240,6 @@ reg_named_capture_assign(struct parser_params* p, VALUE regexp, const rb_code_lo
return RNODE_BLOCK(arg.succ_block)->nd_next;
}
-static VALUE
-rbool(VALUE v)
-{
- return RBOOL(v);
-}
-
static int
rtest(VALUE obj)
{
@@ -351,12 +300,6 @@ arg_error(void)
return rb_eArgError;
}
-static rb_ast_t *
-ast_new(VALUE nb)
-{
- return IMEMO_NEW(rb_ast_t, imemo_ast, nb);
-}
-
static VALUE
static_id2sym(ID id)
{
@@ -364,25 +307,25 @@ static_id2sym(ID id)
}
static long
-str_coderange_scan_restartable(const char *s, const char *e, void *enc, int *cr)
+str_coderange_scan_restartable(const char *s, const char *e, parser_encoding *enc, int *cr)
{
- return rb_str_coderange_scan_restartable(s, e, (rb_encoding *)enc, cr);
+ return rb_str_coderange_scan_restartable(s, e, enc, cr);
}
static int
-enc_mbminlen(void *enc)
+enc_mbminlen(parser_encoding *enc)
{
- return rb_enc_mbminlen((rb_encoding *)enc);
+ return rb_enc_mbminlen(enc);
}
static bool
-enc_isascii(OnigCodePoint c, void *enc)
+enc_isascii(OnigCodePoint c, parser_encoding *enc)
{
- return rb_enc_isascii(c, (rb_encoding *)enc);
+ return rb_enc_isascii(c, enc);
}
static OnigCodePoint
-enc_mbc_to_codepoint(const char *p, const char *e, void *enc)
+enc_mbc_to_codepoint(const char *p, const char *e, parser_encoding *enc)
{
const OnigUChar *up = RBIMPL_CAST((const OnigUChar *)p);
const OnigUChar *ue = RBIMPL_CAST((const OnigUChar *)e);
@@ -390,7 +333,6 @@ enc_mbc_to_codepoint(const char *p, const char *e, void *enc)
return ONIGENC_MBC_TO_CODE((rb_encoding *)enc, up, ue);
}
-VALUE rb_io_gets_internal(VALUE io);
extern VALUE rb_eArgError;
static const rb_parser_config_t rb_global_parser_config = {
@@ -406,8 +348,6 @@ static const rb_parser_config_t rb_global_parser_config = {
.nonempty_memcpy = nonempty_memcpy,
.xmalloc_mul_add = rb_xmalloc_mul_add,
- .ast_new = ast_new,
-
.compile_callback = rb_suppress_tracing,
.reg_named_capture_assign = reg_named_capture_assign,
@@ -417,8 +357,6 @@ static const rb_parser_config_t rb_global_parser_config = {
.ary_push = rb_ary_push,
.ary_new_from_args = rb_ary_new_from_args,
.ary_unshift = rb_ary_unshift,
- .array_len = rb_array_len,
- .array_aref = RARRAY_AREF,
.make_temporary_id = rb_make_temporary_id,
.is_local_id = is_local_id2,
@@ -439,8 +377,6 @@ static const rb_parser_config_t rb_global_parser_config = {
.str_catf = rb_str_catf,
.str_cat_cstr = rb_str_cat_cstr,
- .str_subseq = rb_str_subseq,
- .str_new_frozen = rb_str_new_frozen,
.str_modify = rb_str_modify,
.str_set_len = rb_str_set_len,
.str_cat = rb_str_cat,
@@ -456,7 +392,6 @@ static const rb_parser_config_t rb_global_parser_config = {
.rstring_ptr = RSTRING_PTR,
.rstring_end = RSTRING_END,
.rstring_len = RSTRING_LEN,
- .filesystem_str_new_cstr = rb_filesystem_str_new_cstr,
.obj_as_string = rb_obj_as_string,
.int2num = rb_int2num_inline,
@@ -466,7 +401,6 @@ static const rb_parser_config_t rb_global_parser_config = {
.io_write = rb_io_write,
.io_flush = rb_io_flush,
.io_puts = rb_io_puts,
- .io_gets_internal = rb_io_gets_internal,
.debug_output_stdout = rb_ractor_stdout,
.debug_output_stderr = rb_ractor_stderr,
@@ -485,14 +419,12 @@ static const rb_parser_config_t rb_global_parser_config = {
.ascii8bit_encoding = ascii8bit_encoding,
.enc_codelen = enc_codelen,
.enc_mbcput = enc_mbcput,
+ .enc_mbclen = enc_mbclen,
.enc_find_index = rb_enc_find_index,
.enc_from_index = enc_from_index,
.enc_isspace = enc_isspace,
.enc_coderange_7bit = ENC_CODERANGE_7BIT,
.enc_coderange_unknown = ENC_CODERANGE_UNKNOWN,
- .enc_compatible = enc_compatible,
- .enc_from_encoding = enc_from_encoding,
- .encoding_is_ascii8bit = encoding_is_ascii8bit,
.usascii_encoding = usascii_encoding,
.enc_coderange_broken = ENC_CODERANGE_BROKEN,
.enc_mbminlen = enc_mbminlen,
@@ -534,11 +466,9 @@ static const rb_parser_config_t rb_global_parser_config = {
.scan_digits = ruby_scan_digits,
.strtod = ruby_strtod,
- .rbool = rbool,
.rtest = rtest,
.nil_p = nil_p,
.qnil = Qnil,
- .qtrue = Qtrue,
.qfalse = Qfalse,
.eArgError = arg_error,
.long2int = rb_long2int,
@@ -547,7 +477,77 @@ static const rb_parser_config_t rb_global_parser_config = {
.static_id2sym = static_id2sym,
.str_coderange_scan_restartable = str_coderange_scan_restartable,
};
+#endif
+
+enum lex_type {
+ lex_type_str,
+ lex_type_io,
+ lex_type_array,
+ lex_type_generic,
+};
+
+struct ruby_parser {
+ rb_parser_t *parser_params;
+ enum lex_type type;
+ union {
+ struct lex_pointer_string lex_str;
+ struct {
+ VALUE file;
+ } lex_io;
+ struct {
+ VALUE ary;
+ } lex_array;
+ } data;
+};
+
+static void
+parser_mark(void *ptr)
+{
+ struct ruby_parser *parser = (struct ruby_parser*)ptr;
+ rb_ruby_parser_mark(parser->parser_params);
+
+ switch (parser->type) {
+ case lex_type_str:
+ rb_gc_mark(parser->data.lex_str.str);
+ break;
+ case lex_type_io:
+ rb_gc_mark(parser->data.lex_io.file);
+ break;
+ case lex_type_array:
+ rb_gc_mark(parser->data.lex_array.ary);
+ break;
+ case lex_type_generic:
+ /* noop. Caller of rb_parser_compile_generic should mark the objects. */
+ break;
+ }
+}
+
+static void
+parser_free(void *ptr)
+{
+ struct ruby_parser *parser = (struct ruby_parser*)ptr;
+ rb_ruby_parser_free(parser->parser_params);
+ xfree(parser);
+}
+
+static size_t
+parser_memsize(const void *ptr)
+{
+ struct ruby_parser *parser = (struct ruby_parser*)ptr;
+ return rb_ruby_parser_memsize(parser->parser_params);
+}
+
+static const rb_data_type_t ruby_parser_data_type = {
+ "parser",
+ {
+ parser_mark,
+ parser_free,
+ parser_memsize,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+};
+#ifdef UNIVERSAL_PARSER
const rb_parser_config_t *
rb_ruby_parser_config(void)
{
@@ -555,16 +555,17 @@ rb_ruby_parser_config(void)
}
rb_parser_t *
-rb_parser_params_allocate(void)
+rb_parser_params_new(void)
{
- return rb_ruby_parser_allocate(&rb_global_parser_config);
+ return rb_ruby_parser_new(&rb_global_parser_config);
}
-
+#else
rb_parser_t *
rb_parser_params_new(void)
{
- return rb_ruby_parser_new(&rb_global_parser_config);
+ return rb_ruby_parser_new();
}
+#endif /* UNIVERSAL_PARSER */
VALUE
rb_parser_new(void)
@@ -622,65 +623,239 @@ rb_parser_error_tolerant(VALUE vparser)
rb_ruby_parser_error_tolerant(parser->parser_params);
}
-rb_ast_t*
-rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE file, int start)
+void
+rb_parser_keep_tokens(VALUE vparser)
{
struct ruby_parser *parser;
+
+ TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
+ rb_ruby_parser_keep_tokens(parser->parser_params);
+}
+
+rb_parser_string_t *
+rb_parser_lex_get_str(struct parser_params *p, struct lex_pointer_string *ptr_str)
+{
+ char *beg, *end, *start;
+ long len;
+ VALUE s = ptr_str->str;
+
+ beg = RSTRING_PTR(s);
+ len = RSTRING_LEN(s);
+ start = beg;
+ if (ptr_str->ptr) {
+ if (len == ptr_str->ptr) return 0;
+ beg += ptr_str->ptr;
+ len -= ptr_str->ptr;
+ }
+ end = memchr(beg, '\n', len);
+ if (end) len = ++end - beg;
+ ptr_str->ptr += len;
+ return rb_str_to_parser_string(p, rb_str_subseq(s, beg - start, len));
+}
+
+static rb_parser_string_t *
+lex_get_str(struct parser_params *p, rb_parser_input_data input, int line_count)
+{
+ return rb_parser_lex_get_str(p, (struct lex_pointer_string *)input);
+}
+
+static void parser_aset_script_lines_for(VALUE path, rb_parser_ary_t *lines);
+
+static rb_ast_t*
+parser_compile(rb_parser_t *p, rb_parser_lex_gets_func *gets, VALUE fname, rb_parser_input_data input, int line)
+{
rb_ast_t *ast;
+ const char *ptr = 0;
+ long len = 0;
+ rb_encoding *enc = 0;
+
+ if (!NIL_P(fname)) {
+ StringValueCStr(fname);
+ ptr = RSTRING_PTR(fname);
+ len = RSTRING_LEN(fname);
+ enc = rb_enc_get(fname);
+ }
+
+ ast = rb_parser_compile(p, gets, ptr, len, enc, input, line);
+ parser_aset_script_lines_for(fname, ast->body.script_lines);
+ return ast;
+}
+
+static rb_ast_t*
+parser_compile_string0(struct ruby_parser *parser, VALUE fname, VALUE s, int line)
+{
+ VALUE str = rb_str_new_frozen(s);
+
+ parser->type = lex_type_str;
+ parser->data.lex_str.str = str;
+ parser->data.lex_str.ptr = 0;
+
+ return parser_compile(parser->parser_params, lex_get_str, fname, (rb_parser_input_data)&parser->data, line);
+}
+
+static rb_encoding *
+must_be_ascii_compatible(VALUE s)
+{
+ rb_encoding *enc = rb_enc_get(s);
+ if (!rb_enc_asciicompat(enc)) {
+ rb_raise(rb_eArgError, "invalid source encoding");
+ }
+ return enc;
+}
+
+static rb_ast_t*
+parser_compile_string_path(struct ruby_parser *parser, VALUE f, VALUE s, int line)
+{
+ must_be_ascii_compatible(s);
+ return parser_compile_string0(parser, f, s, line);
+}
+
+static rb_ast_t*
+parser_compile_string(struct ruby_parser *parser, const char *f, VALUE s, int line)
+{
+ return parser_compile_string_path(parser, rb_filesystem_str_new_cstr(f), s, line);
+}
+
+VALUE rb_io_gets_internal(VALUE io);
+
+static rb_parser_string_t *
+lex_io_gets(struct parser_params *p, rb_parser_input_data input, int line_count)
+{
+ VALUE io = (VALUE)input;
+ VALUE line = rb_io_gets_internal(io);
+ if (NIL_P(line)) return 0;
+ return rb_str_to_parser_string(p, line);
+}
+
+static rb_parser_string_t *
+lex_gets_array(struct parser_params *p, rb_parser_input_data data, int index)
+{
+ VALUE array = (VALUE)data;
+ VALUE str = rb_ary_entry(array, index);
+ if (!NIL_P(str)) {
+ StringValue(str);
+ if (!rb_enc_asciicompat(rb_enc_get(str))) {
+ rb_raise(rb_eArgError, "invalid source encoding");
+ }
+ return rb_str_to_parser_string(p, str);
+ }
+ else {
+ return 0;
+ }
+}
+
+static rb_ast_t*
+parser_compile_file_path(struct ruby_parser *parser, VALUE fname, VALUE file, int start)
+{
+ parser->type = lex_type_io;
+ parser->data.lex_io.file = file;
+
+ return parser_compile(parser->parser_params, lex_io_gets, fname, (rb_parser_input_data)file, start);
+}
+
+static rb_ast_t*
+parser_compile_array(struct ruby_parser *parser, VALUE fname, VALUE array, int start)
+{
+ parser->type = lex_type_array;
+ parser->data.lex_array.ary = array;
+
+ return parser_compile(parser->parser_params, lex_gets_array, fname, (rb_parser_input_data)array, start);
+}
+
+static rb_ast_t*
+parser_compile_generic(struct ruby_parser *parser, rb_parser_lex_gets_func *lex_gets, VALUE fname, VALUE input, int start)
+{
+ parser->type = lex_type_generic;
+
+ return parser_compile(parser->parser_params, lex_gets, fname, (rb_parser_input_data)input, start);
+}
+
+static void
+ast_free(void *ptr)
+{
+ rb_ast_t *ast = (rb_ast_t *)ptr;
+ rb_ast_free(ast);
+}
+
+static const rb_data_type_t ast_data_type = {
+ "AST",
+ {
+ NULL,
+ ast_free,
+ NULL, // No dsize() because this object does not appear in ObjectSpace.
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+};
+
+static VALUE
+ast_alloc(void)
+{
+ return TypedData_Wrap_Struct(0, &ast_data_type, NULL);
+}
+
+VALUE
+rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE file, int start)
+{
+ struct ruby_parser *parser;
+ VALUE ast_value = ast_alloc();
TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- ast = rb_ruby_parser_compile_file_path(parser->parser_params, fname, file, start);
+ DATA_PTR(ast_value) = parser_compile_file_path(parser, fname, file, start);
RB_GC_GUARD(vparser);
- return ast;
+ return ast_value;
}
-void
-rb_parser_keep_tokens(VALUE vparser)
+VALUE
+rb_parser_compile_array(VALUE vparser, VALUE fname, VALUE array, int start)
{
struct ruby_parser *parser;
+ VALUE ast_value = ast_alloc();
TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_keep_tokens(parser->parser_params);
+ DATA_PTR(ast_value) = parser_compile_array(parser, fname, array, start);
+ RB_GC_GUARD(vparser);
+
+ return ast_value;
}
-rb_ast_t*
-rb_parser_compile_generic(VALUE vparser, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int start)
+VALUE
+rb_parser_compile_generic(VALUE vparser, rb_parser_lex_gets_func *lex_gets, VALUE fname, VALUE input, int start)
{
struct ruby_parser *parser;
- rb_ast_t *ast;
+ VALUE ast_value = ast_alloc();
TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- ast = rb_ruby_parser_compile_generic(parser->parser_params, lex_gets, fname, input, start);
+ DATA_PTR(ast_value) = parser_compile_generic(parser, lex_gets, fname, input, start);
RB_GC_GUARD(vparser);
- return ast;
+ return ast_value;
}
-rb_ast_t*
+VALUE
rb_parser_compile_string(VALUE vparser, const char *f, VALUE s, int line)
{
struct ruby_parser *parser;
- rb_ast_t *ast;
+ VALUE ast_value = ast_alloc();
TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- ast = rb_ruby_parser_compile_string(parser->parser_params, f, s, line);
+ DATA_PTR(ast_value) = parser_compile_string(parser, f, s, line);
RB_GC_GUARD(vparser);
- return ast;
+ return ast_value;
}
-rb_ast_t*
+VALUE
rb_parser_compile_string_path(VALUE vparser, VALUE f, VALUE s, int line)
{
struct ruby_parser *parser;
- rb_ast_t *ast;
+ VALUE ast_value = ast_alloc();
TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- ast = rb_ruby_parser_compile_string_path(parser->parser_params, f, s, line);
+ DATA_PTR(ast_value) = parser_compile_string_path(parser, f, s, line);
RB_GC_GUARD(vparser);
- return ast;
+ return ast_value;
}
VALUE
@@ -689,7 +864,7 @@ rb_parser_encoding(VALUE vparser)
struct ruby_parser *parser;
TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- return rb_ruby_parser_encoding(parser->parser_params);
+ return rb_enc_from_encoding(rb_ruby_parser_encoding(parser->parser_params));
}
VALUE
@@ -726,12 +901,12 @@ rb_set_script_lines_for(VALUE vparser, VALUE path)
rb_ruby_parser_set_script_lines(parser->parser_params);
}
}
-#endif
VALUE
rb_parser_build_script_lines_from(rb_parser_ary_t *lines)
{
int i;
+ if (!lines) return Qnil;
if (lines->data_type != PARSER_ARY_DATA_SCRIPT_LINE) {
rb_bug("unexpected rb_parser_ary_data_type (%d) for script lines", lines->data_type);
}
@@ -949,12 +1124,12 @@ rb_node_encoding_val(const NODE *node)
return rb_enc_from_encoding(RNODE_ENCODING(node)->enc);
}
-void
-rb_parser_aset_script_lines_for(VALUE path, rb_parser_ary_t *lines)
+static void
+parser_aset_script_lines_for(VALUE path, rb_parser_ary_t *lines)
{
VALUE hash, script_lines;
ID script_lines_id;
- if (NIL_P(path) || !lines || FIXNUM_P((VALUE)lines)) return;
+ if (NIL_P(path) || !lines) return;
CONST_ID(script_lines_id, "SCRIPT_LINES__");
if (!rb_const_defined_at(rb_cObject, script_lines_id)) return;
hash = rb_const_get_at(rb_cObject, script_lines_id);
@@ -963,3 +1138,30 @@ rb_parser_aset_script_lines_for(VALUE path, rb_parser_ary_t *lines)
script_lines = rb_parser_build_script_lines_from(lines);
rb_hash_aset(hash, path, script_lines);
}
+
+VALUE
+rb_ruby_ast_new(const NODE *const root)
+{
+ rb_ast_t *ast;
+ VALUE ast_value = TypedData_Make_Struct(0, rb_ast_t, &ast_data_type, ast);
+#ifdef UNIVERSAL_PARSER
+ ast->config = &rb_global_parser_config;
+#endif
+ ast->body = (rb_ast_body_t){
+ .root = root,
+ .frozen_string_literal = -1,
+ .coverage_enabled = -1,
+ .script_lines = NULL,
+ .line_count = 0,
+ };
+ return ast_value;
+}
+
+rb_ast_t *
+rb_ruby_ast_data_get(VALUE ast_value)
+{
+ rb_ast_t *ast;
+ if (NIL_P(ast_value)) return NULL;
+ TypedData_Get_Struct(ast_value, rb_ast_t, &ast_data_type, ast);
+ return ast;
+}
diff --git a/rubyparser.h b/rubyparser.h
index 6d346a7ff4..fc8be9633a 100644
--- a/rubyparser.h
+++ b/rubyparser.h
@@ -9,7 +9,7 @@
#ifdef UNIVERSAL_PARSER
-#define rb_encoding void
+#define rb_encoding const void
#define OnigCodePoint unsigned int
#include "parser_st.h"
#ifndef RUBY_RUBY_H
@@ -73,6 +73,8 @@ enum rb_parser_shareability {
rb_parser_shareable_everything,
};
+typedef void* rb_parser_input_data;
+
/*
* AST Node
*/
@@ -1206,20 +1208,24 @@ typedef struct RNode_ERROR {
(n)->flags=(((n)->flags&~NODE_TYPEMASK)|((((unsigned long)(t))<<NODE_TYPESHIFT)&NODE_TYPEMASK))
typedef struct node_buffer_struct node_buffer_t;
-/* T_IMEMO/ast */
+
+#ifdef UNIVERSAL_PARSER
+typedef struct rb_parser_config_struct rb_parser_config_t;
+#endif
+
typedef struct rb_ast_body_struct {
const NODE *root;
rb_parser_ary_t *script_lines;
- // script_lines is either:
- // - a Fixnum that represents the line count of the original source, or
- // - an rb_parser_ary_t* that contains the lines of the original source
+ int line_count;
signed int frozen_string_literal:2; /* -1: not specified, 0: false, 1: true */
signed int coverage_enabled:2; /* -1: not specified, 0: false, 1: true */
} rb_ast_body_t;
typedef struct rb_ast_struct {
- VALUE flags;
node_buffer_t *node_buffer;
rb_ast_body_t body;
+#ifdef UNIVERSAL_PARSER
+ const rb_parser_config_t *config;
+#endif
} rb_ast_t;
@@ -1249,9 +1255,6 @@ typedef struct rb_parser_config_struct {
void *(*nonempty_memcpy)(void *dest, const void *src, size_t t, size_t n);
void *(*xmalloc_mul_add)(size_t x, size_t y, size_t z);
- /* imemo */
- rb_ast_t *(*ast_new)(VALUE nb);
-
// VALUE rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg);
VALUE (*compile_callback)(VALUE (*func)(VALUE), VALUE arg);
NODE *(*reg_named_capture_assign)(struct parser_params* p, VALUE regexp, const rb_code_location_t *loc);
@@ -1264,8 +1267,6 @@ typedef struct rb_parser_config_struct {
VALUE (*ary_push)(VALUE ary, VALUE elem);
VALUE (*ary_new_from_args)(long n, ...);
VALUE (*ary_unshift)(VALUE ary, VALUE item);
- long (*array_len)(VALUE a);
- VALUE (*array_aref)(VALUE, long);
/* Symbol */
ID (*make_temporary_id)(size_t n);
@@ -1289,8 +1290,6 @@ typedef struct rb_parser_config_struct {
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
VALUE (*str_catf)(VALUE str, const char *format, ...);
VALUE (*str_cat_cstr)(VALUE str, const char *ptr);
- VALUE (*str_subseq)(VALUE str, long beg, long len);
- VALUE (*str_new_frozen)(VALUE orig);
void (*str_modify)(VALUE str);
void (*str_set_len)(VALUE str, long len);
VALUE (*str_cat)(VALUE str, const char *ptr, long len);
@@ -1308,7 +1307,6 @@ typedef struct rb_parser_config_struct {
char *(*rstring_ptr)(VALUE str);
char *(*rstring_end)(VALUE str);
long (*rstring_len)(VALUE str);
- VALUE (*filesystem_str_new_cstr)(const char *ptr);
VALUE (*obj_as_string)(VALUE);
/* Numeric */
@@ -1320,7 +1318,6 @@ typedef struct rb_parser_config_struct {
VALUE (*io_write)(VALUE io, VALUE str);
VALUE (*io_flush)(VALUE io);
VALUE (*io_puts)(int argc, const VALUE *argv, VALUE out);
- VALUE (*io_gets_internal)(VALUE io);
/* IO (Ractor) */
VALUE (*debug_output_stdout)(void);
@@ -1341,12 +1338,10 @@ typedef struct rb_parser_config_struct {
rb_encoding *(*ascii8bit_encoding)(void);
int (*enc_codelen)(int c, rb_encoding *enc);
int (*enc_mbcput)(unsigned int c, void *buf, rb_encoding *enc);
+ int (*enc_mbclen)(const char *p, const char *e, rb_encoding *enc);
int (*enc_find_index)(const char *name);
rb_encoding *(*enc_from_index)(int idx);
int (*enc_isspace)(OnigCodePoint c, rb_encoding *enc);
- rb_encoding *(*enc_compatible)(VALUE str1, VALUE str2);
- VALUE (*enc_from_encoding)(rb_encoding *enc);
- int (*encoding_is_ascii8bit)(VALUE obj);
rb_encoding *(*usascii_encoding)(void);
int enc_coderange_broken;
int (*enc_mbminlen)(rb_encoding *enc);
@@ -1401,11 +1396,9 @@ typedef struct rb_parser_config_struct {
double (*strtod)(const char *s00, char **se);
/* Misc */
- VALUE (*rbool)(VALUE);
int (*rtest)(VALUE obj);
int (*nil_p)(VALUE obj);
VALUE qnil;
- VALUE qtrue;
VALUE qfalse;
VALUE (*eArgError)(void);
int (*long2int)(long);
@@ -1423,7 +1416,6 @@ typedef struct rb_parser_config_struct {
RUBY_SYMBOL_EXPORT_BEGIN
void rb_ruby_parser_free(void *ptr);
-rb_ast_t* rb_ruby_parser_compile_string(rb_parser_t *p, const char *f, VALUE s, int line);
#ifdef UNIVERSAL_PARSER
rb_parser_t *rb_ruby_parser_allocate(const rb_parser_config_t *config);
diff --git a/shape.c b/shape.c
index 1158aad52c..0f9e3d54fa 100644
--- a/shape.c
+++ b/shape.c
@@ -118,6 +118,7 @@ redblack_value(redblack_node_t * node)
return (rb_shape_t *)((uintptr_t)node->value & (((uintptr_t)-1) - 1));
}
+#ifdef HAVE_MMAP
static redblack_id_t
redblack_id_for(redblack_node_t * node)
{
@@ -292,6 +293,7 @@ redblack_insert(redblack_node_t * tree, ID key, rb_shape_t * value)
return root;
}
}
+#endif
rb_shape_tree_t *rb_shape_tree_ptr = NULL;
@@ -1213,9 +1215,7 @@ rb_shape_find_by_id(VALUE mod, VALUE id)
void
Init_default_shapes(void)
{
- rb_shape_tree_t *st = ruby_mimmalloc(sizeof(rb_shape_tree_t));
- memset(st, 0, sizeof(rb_shape_tree_t));
- rb_shape_tree_ptr = st;
+ rb_shape_tree_ptr = xcalloc(1, sizeof(rb_shape_tree_t));
#ifdef HAVE_MMAP
rb_shape_tree_ptr->shape_list = (rb_shape_t *)mmap(NULL, rb_size_mul_or_raise(SHAPE_BUFFER_SIZE, sizeof(rb_shape_t), rb_eRuntimeError),
diff --git a/spec/bundler/commands/cache_spec.rb b/spec/bundler/commands/cache_spec.rb
index 70e2c84961..37d8b3ac1a 100644
--- a/spec/bundler/commands/cache_spec.rb
+++ b/spec/bundler/commands/cache_spec.rb
@@ -386,6 +386,66 @@ RSpec.describe "bundle install with gem sources" do
expect(the_bundle).to include_gems "rack 1.0.0"
end
+ it "uses cached gems for secondary sources when cache_all_platforms configured" do
+ build_repo4 do
+ build_gem "foo", "1.0.0" do |s|
+ s.platform = "x86_64-linux"
+ end
+
+ build_gem "foo", "1.0.0" do |s|
+ s.platform = "arm64-darwin"
+ end
+ end
+
+ gemfile <<~G
+ source "https://gems.repo2"
+
+ source "https://gems.repo4" do
+ gem "foo"
+ end
+ G
+
+ lockfile <<~L
+ GEM
+ remote: https://gems.repo2/
+ specs:
+
+ GEM
+ remote: https://gems.repo4/
+ specs:
+ foo (1.0.0-x86_64-linux)
+ foo (1.0.0-arm64-darwin)
+
+ PLATFORMS
+ arm64-darwin
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ foo
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ simulate_platform "x86_64-linux" do
+ bundle "config set cache_all_platforms true"
+ bundle "config set path vendor/bundle"
+ bundle :cache, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ build_repo4 do
+ # simulate removal of all remote gems
+ end
+
+ # delete compact index cache
+ FileUtils.rm_rf home(".bundle/cache/compact_index")
+
+ bundle "install", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ expect(the_bundle).to include_gems "foo 1.0.0 x86_64-linux"
+ end
+ end
+
it "does not reinstall already-installed gems" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
diff --git a/spec/bundler/commands/help_spec.rb b/spec/bundler/commands/help_spec.rb
index 535df8e35a..0c7031e813 100644
--- a/spec/bundler/commands/help_spec.rb
+++ b/spec/bundler/commands/help_spec.rb
@@ -15,6 +15,13 @@ RSpec.describe "bundle help" do
expect(out).to eq(%(["#{man_dir}/bundle-install.1"]))
end
+ it "prexifes bundle commands with bundle- and resolves aliases when finding the man files" do
+ with_fake_man do
+ bundle "help package"
+ end
+ expect(out).to eq(%(["#{man_dir}/bundle-cache.1"]))
+ end
+
it "simply outputs the human readable file when there is no man on the path" do
with_path_as("") do
bundle "help install"
diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb
index f0c9aaea8e..edc5887d7b 100644
--- a/spec/bundler/commands/install_spec.rb
+++ b/spec/bundler/commands/install_spec.rb
@@ -1024,6 +1024,29 @@ RSpec.describe "bundle install with gem sources" do
end
end
+ describe "when gemspecs are unreadable", :permissions do
+ let(:gemspec_path) { vendored_gems("specifications/rack-1.0.0.gemspec") }
+
+ before do
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
+ G
+ bundle "config path vendor/bundle"
+ bundle :install
+ expect(out).to include("Bundle complete!")
+ expect(err).to be_empty
+
+ FileUtils.chmod("-r", gemspec_path)
+ end
+
+ it "shows a good error" do
+ bundle :install, raise_on_error: false
+ expect(err).to include(gemspec_path.to_s)
+ expect(err).to include("grant read permissions")
+ end
+ end
+
context "after installing with --standalone" do
before do
install_gemfile <<-G
@@ -1384,4 +1407,33 @@ RSpec.describe "bundle install with gem sources" do
expect(bundled_app(".bundle/config")).not_to exist
end
end
+
+ context "when bundler installation is corrupt" do
+ before do
+ system_gems "bundler-9.99.8"
+
+ replace_version_file("9.99.9", dir: system_gem_path("gems/bundler-9.99.8"))
+ end
+
+ it "shows a proper error" do
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+
+ BUNDLED WITH
+ 9.99.8
+ L
+
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"", env: { "BUNDLER_VERSION" => "9.99.8" }, raise_on_error: false
+
+ expect(err).not_to include("ERROR REPORT TEMPLATE")
+ expect(err).to include("The running version of Bundler (9.99.9) does not match the version of the specification installed for it (9.99.8)")
+ end
+ end
end
diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb
index f6793d393b..c6bb0f58af 100644
--- a/spec/bundler/commands/lock_spec.rb
+++ b/spec/bundler/commands/lock_spec.rb
@@ -252,6 +252,128 @@ RSpec.describe "bundle lock" do
expect(read_lockfile).to eq(remove_checksums_from_lockfile(@lockfile, "(2.3.2)", "(#{rake_version})"))
end
+ it "updates specific gems using --update, even if that requires unlocking other top level gems" do
+ build_repo4 do
+ build_gem "prism", "0.15.1"
+ build_gem "prism", "0.24.0"
+
+ build_gem "ruby-lsp", "0.12.0" do |s|
+ s.add_dependency "prism", "< 0.24.0"
+ end
+
+ build_gem "ruby-lsp", "0.16.1" do |s|
+ s.add_dependency "prism", ">= 0.24.0"
+ end
+
+ build_gem "tapioca", "0.11.10" do |s|
+ s.add_dependency "prism", "< 0.24.0"
+ end
+
+ build_gem "tapioca", "0.13.1" do |s|
+ s.add_dependency "prism", ">= 0.24.0"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "tapioca"
+ gem "ruby-lsp"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}
+ specs:
+ prism (0.15.1)
+ ruby-lsp (0.12.0)
+ prism (< 0.24.0)
+ tapioca (0.11.10)
+ prism (< 0.24.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ruby-lsp
+ tapioca
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "lock --update tapioca --verbose"
+
+ expect(lockfile).to include("tapioca (0.13.1)")
+ end
+
+ it "updates specific gems using --update, even if that requires unlocking other top level gems, but only as few as possible" do
+ build_repo4 do
+ build_gem "prism", "0.15.1"
+ build_gem "prism", "0.24.0"
+
+ build_gem "ruby-lsp", "0.12.0" do |s|
+ s.add_dependency "prism", "< 0.24.0"
+ end
+
+ build_gem "ruby-lsp", "0.16.1" do |s|
+ s.add_dependency "prism", ">= 0.24.0"
+ end
+
+ build_gem "tapioca", "0.11.10" do |s|
+ s.add_dependency "prism", "< 0.24.0"
+ end
+
+ build_gem "tapioca", "0.13.1" do |s|
+ s.add_dependency "prism", ">= 0.24.0"
+ end
+
+ build_gem "other-prism-dependent", "1.0.0" do |s|
+ s.add_dependency "prism", ">= 0.15.1"
+ end
+
+ build_gem "other-prism-dependent", "1.1.0" do |s|
+ s.add_dependency "prism", ">= 0.15.1"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "tapioca"
+ gem "ruby-lsp"
+ gem "other-prism-dependent"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}
+ specs:
+ other-prism-dependent (1.0.0)
+ prism (>= 0.15.1)
+ prism (0.15.1)
+ ruby-lsp (0.12.0)
+ prism (< 0.24.0)
+ tapioca (0.11.10)
+ prism (< 0.24.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ruby-lsp
+ tapioca
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "lock --update tapioca"
+
+ expect(lockfile).to include("tapioca (0.13.1)")
+ expect(lockfile).to include("other-prism-dependent (1.0.0)")
+ end
+
it "preserves unknown checksum algorithms" do
lockfile @lockfile.gsub(/(sha256=[a-f0-9]+)$/, "constant=true,\\1,xyz=123")
diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb
index cfb86ebb54..8565e27ebf 100644
--- a/spec/bundler/commands/update_spec.rb
+++ b/spec/bundler/commands/update_spec.rb
@@ -1954,6 +1954,52 @@ RSpec.describe "bundle update conservative" do
end
end
+ context "when Gemfile dependencies have changed" do
+ before do
+ build_repo4 do
+ build_gem "nokogiri", "1.16.4" do |s|
+ s.platform = "arm64-darwin"
+ end
+
+ build_gem "nokogiri", "1.16.4" do |s|
+ s.platform = "x86_64-linux"
+ end
+
+ build_gem "prism", "0.25.0"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "nokogiri", ">=1.16.4"
+ gem "prism", ">=0.25.0"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.16.4-arm64-darwin)
+ nokogiri (1.16.4-x86_64-linux)
+
+ PLATFORMS
+ arm64-darwin
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri (>= 1.16.4)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "still works" do
+ simulate_platform "arm64-darwin-23" do
+ bundle "update"
+ end
+ end
+ end
+
context "error handling" do
before do
gemfile "source \"#{file_uri_for(gem_repo1)}\""
diff --git a/spec/bundler/install/deploy_spec.rb b/spec/bundler/install/deploy_spec.rb
index 8002978368..d89fdea6f1 100644
--- a/spec/bundler/install/deploy_spec.rb
+++ b/spec/bundler/install/deploy_spec.rb
@@ -183,50 +183,10 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "config set --local deployment true"
end
- it "prevents the replace by default" do
- bundle :install, raise_on_error: false
-
- expect(err).to match(/The list of sources changed/)
- end
-
- context "when allow_deployment_source_credential_changes is true" do
- before { bundle "config set allow_deployment_source_credential_changes true" }
-
- it "allows the replace" do
- bundle :install
-
- expect(out).to match(/Bundle complete!/)
- end
- end
-
- context "when allow_deployment_source_credential_changes is false" do
- before { bundle "config set allow_deployment_source_credential_changes false" }
-
- it "prevents the replace" do
- bundle :install, raise_on_error: false
-
- expect(err).to match(/The list of sources changed/)
- end
- end
-
- context "when BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES env var is true" do
- before { ENV["BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES"] = "true" }
-
- it "allows the replace" do
- bundle :install
-
- expect(out).to match(/Bundle complete!/)
- end
- end
-
- context "when BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES env var is false" do
- before { ENV["BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES"] = "false" }
-
- it "prevents the replace" do
- bundle :install, raise_on_error: false
+ it "allows the replace" do
+ bundle :install
- expect(err).to match(/The list of sources changed/)
- end
+ expect(out).to match(/Bundle complete!/)
end
end
diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb
index 7f664abc4d..4fd081e7d0 100644
--- a/spec/bundler/lock/lockfile_spec.rb
+++ b/spec/bundler/lock/lockfile_spec.rb
@@ -324,7 +324,7 @@ RSpec.describe "the lockfile format" do
G
end
- it "generates a lockfile without credentials for a configured source" do
+ it "generates a lockfile without credentials" do
bundle "config set http://localgemserver.test/ user:pass"
install_gemfile(<<-G, artifice: "endpoint_strict_basic_authentication", quiet: true)
@@ -354,7 +354,7 @@ RSpec.describe "the lockfile format" do
specs:
GEM
- remote: http://user:pass@othergemserver.test/
+ remote: http://othergemserver.test/
specs:
rack (1.0.0)
rack-obama (1.0)
diff --git a/spec/bundler/plugins/hook_spec.rb b/spec/bundler/plugins/hook_spec.rb
index 72feb14d84..f6ee0ba210 100644
--- a/spec/bundler/plugins/hook_spec.rb
+++ b/spec/bundler/plugins/hook_spec.rb
@@ -106,4 +106,103 @@ RSpec.describe "hook plugins" do
expect(out).to include "installed gem rack : installed"
end
end
+
+ context "before-require-all hook" do
+ before do
+ build_repo2 do
+ build_plugin "before-require-all-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_BEFORE_REQUIRE_ALL do |deps|
+ puts "gems to be required \#{deps.map(&:name).join(", ")}"
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install before-require-all-plugin --source #{file_uri_for(gem_repo2)}"
+ end
+
+ it "runs before all rubygems are required" do
+ install_gemfile_and_bundler_require
+ expect(out).to include "gems to be required rake, rack"
+ end
+ end
+
+ context "before-require hook" do
+ before do
+ build_repo2 do
+ build_plugin "before-require-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_BEFORE_REQUIRE do |dep|
+ puts "requiring gem \#{dep.name}"
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install before-require-plugin --source #{file_uri_for(gem_repo2)}"
+ end
+
+ it "runs before each rubygem is required" do
+ install_gemfile_and_bundler_require
+ expect(out).to include "requiring gem rake"
+ expect(out).to include "requiring gem rack"
+ end
+ end
+
+ context "after-require-all hook" do
+ before do
+ build_repo2 do
+ build_plugin "after-require-all-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_AFTER_REQUIRE_ALL do |deps|
+ puts "required gems \#{deps.map(&:name).join(", ")}"
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install after-require-all-plugin --source #{file_uri_for(gem_repo2)}"
+ end
+
+ it "runs after all rubygems are required" do
+ install_gemfile_and_bundler_require
+ expect(out).to include "required gems rake, rack"
+ end
+ end
+
+ context "after-require hook" do
+ before do
+ build_repo2 do
+ build_plugin "after-require-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_AFTER_REQUIRE do |dep|
+ puts "required gem \#{dep.name}"
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install after-require-plugin --source #{file_uri_for(gem_repo2)}"
+ end
+
+ it "runs after each rubygem is required" do
+ install_gemfile_and_bundler_require
+ expect(out).to include "required gem rake"
+ expect(out).to include "required gem rack"
+ end
+ end
+
+ def install_gemfile_and_bundler_require
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rake"
+ gem "rack"
+ G
+
+ ruby <<-RUBY
+ require "bundler"
+ Bundler.require
+ RUBY
+ end
end
diff --git a/spec/bundler/runtime/inline_spec.rb b/spec/bundler/runtime/inline_spec.rb
index ffac30d6d8..50a5258dc7 100644
--- a/spec/bundler/runtime/inline_spec.rb
+++ b/spec/bundler/runtime/inline_spec.rb
@@ -638,4 +638,22 @@ RSpec.describe "bundler/inline#gemfile" do
expect(out).to include("Installing timeout 999")
end
+
+ it "does not upcase ENV" do
+ script <<-RUBY
+ require 'bundler/inline'
+
+ ENV['Test_Variable'] = 'value string'
+ puts("before: \#{ENV.each_key.select { |key| key.match?(/test_variable/i) }}")
+
+ gemfile do
+ source "#{file_uri_for(gem_repo1)}"
+ end
+
+ puts("after: \#{ENV.each_key.select { |key| key.match?(/test_variable/i) }}")
+ RUBY
+
+ expect(out).to include("before: [\"Test_Variable\"]")
+ expect(out).to include("after: [\"Test_Variable\"]")
+ end
end
diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb
index ccfe5d55b6..2d78825de4 100644
--- a/spec/bundler/runtime/setup_spec.rb
+++ b/spec/bundler/runtime/setup_spec.rb
@@ -767,6 +767,18 @@ end
expect(err).to be_empty
end
+ it "can require rubygems without warnings, when using a local cache", rubygems: ">= 3.5.10" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ G
+
+ bundle "package"
+ bundle %(exec ruby -w -e "require 'rubygems'")
+
+ expect(err).to be_empty
+ end
+
context "when the user has `MANPATH` set", :man do
before { ENV["MANPATH"] = "/foo#{File::PATH_SEPARATOR}" }
@@ -1599,4 +1611,19 @@ end
sys_exec "#{Gem.ruby} #{script}", raise_on_error: false
expect(out).to include("requiring foo used the monkeypatch")
end
+
+ it "performs an automatic bundle install" do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :group => :test
+ G
+
+ bundle "config set auto_install 1"
+
+ ruby <<-RUBY
+ require 'bundler/setup'
+ RUBY
+ expect(err).to be_empty
+ expect(out).to include("Installing rack 1.0.0")
+ end
end
diff --git a/spec/bundler/runtime/with_unbundled_env_spec.rb b/spec/bundler/runtime/with_unbundled_env_spec.rb
index 84b198cfb6..135c71b0af 100644
--- a/spec/bundler/runtime/with_unbundled_env_spec.rb
+++ b/spec/bundler/runtime/with_unbundled_env_spec.rb
@@ -139,7 +139,7 @@ RSpec.describe "Bundler.with_env helpers" do
describe "Bundler.with_original_env" do
it "should set ENV to original_env in the block" do
expected = Bundler.original_env
- actual = Bundler.with_original_env { Bundler::EnvironmentPreserver.env_to_hash(ENV) }
+ actual = Bundler.with_original_env { ENV.to_hash }
expect(actual).to eq(expected)
end
@@ -157,7 +157,7 @@ RSpec.describe "Bundler.with_env helpers" do
expected = Bundler.unbundled_env
actual = Bundler.ui.silence do
- Bundler.with_clean_env { Bundler::EnvironmentPreserver.env_to_hash(ENV) }
+ Bundler.with_clean_env { ENV.to_hash }
end
expect(actual).to eq(expected)
@@ -175,7 +175,7 @@ RSpec.describe "Bundler.with_env helpers" do
describe "Bundler.with_unbundled_env" do
it "should set ENV to unbundled_env in the block" do
expected = Bundler.unbundled_env
- actual = Bundler.with_unbundled_env { Bundler::EnvironmentPreserver.env_to_hash(ENV) }
+ actual = Bundler.with_unbundled_env { ENV.to_hash }
expect(actual).to eq(expected)
end
diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb
index ab2dafb0b9..8f646b9358 100644
--- a/spec/bundler/support/builders.rb
+++ b/spec/bundler/support/builders.rb
@@ -518,7 +518,6 @@ module Spec
if options[:rubygems_version]
@spec.rubygems_version = options[:rubygems_version]
- def @spec.mark_version; end
def @spec.validate(*); end
end
diff --git a/spec/prism.mspec b/spec/prism.mspec
index 16508bd547..42956c6e7b 100644
--- a/spec/prism.mspec
+++ b/spec/prism.mspec
@@ -1,45 +1,4 @@
# frozen_string_literal: true
-# This is turned off because when we run with --parser=prism we explicitly turn
-# off experimental warnings to make sure the output is consistent.
-MSpec.register(:exclude, "Warning.[] returns default values for categories :deprecated and :experimental")
-
-## Language
-MSpec.register(:exclude, "Hash literal expands an '**{}' or '**obj' element with the last key/value pair taking precedence")
-MSpec.register(:exclude, "Hash literal expands an '**{}' and warns when finding an additional duplicate key afterwards")
-MSpec.register(:exclude, "Hash literal merges multiple nested '**obj' in Hash literals")
-MSpec.register(:exclude, "Hash literal raises a SyntaxError at parse time when Symbol key with invalid bytes")
-MSpec.register(:exclude, "Hash literal raises a SyntaxError at parse time when Symbol key with invalid bytes and 'key: value' syntax used")
-MSpec.register(:exclude, "Regexps with encoding modifiers supports /e (EUC encoding) with interpolation")
-MSpec.register(:exclude, "Regexps with encoding modifiers supports /e (EUC encoding) with interpolation /o")
-MSpec.register(:exclude, "Regexps with encoding modifiers preserves EUC-JP as /e encoding through interpolation")
-MSpec.register(:exclude, "Regexps with encoding modifiers supports /s (Windows_31J encoding) with interpolation")
-MSpec.register(:exclude, "Regexps with encoding modifiers supports /s (Windows_31J encoding) with interpolation and /o")
-MSpec.register(:exclude, "Regexps with encoding modifiers preserves Windows-31J as /s encoding through interpolation")
-MSpec.register(:exclude, "Regexps with encoding modifiers supports /u (UTF8 encoding) with interpolation")
-MSpec.register(:exclude, "Regexps with encoding modifiers supports /u (UTF8 encoding) with interpolation and /o")
-MSpec.register(:exclude, "Regexps with encoding modifiers preserves UTF-8 as /u encoding through interpolation")
-MSpec.register(:exclude, "A Symbol literal raises an SyntaxError at parse time when Symbol with invalid bytes")
-
-## Core
-MSpec.register(:exclude, "IO.popen with a leading Array argument accepts a trailing Hash of Process.exec options")
-MSpec.register(:exclude, "IO.popen with a leading Array argument accepts an IO mode argument following the Array")
-MSpec.register(:exclude, "TracePoint#inspect returns a String showing the event, method, path and line for a :return event")
-MSpec.register(:exclude, "TracePoint.new includes multiple events when multiple event names are passed as params")
-MSpec.register(:exclude, "TracePoint#path equals \"(eval at __FILE__:__LINE__)\" inside an eval for :end event")
-
-## Library
-MSpec.register(:exclude, "Coverage.peek_result returns the result so far")
-MSpec.register(:exclude, "Coverage.peek_result second call after require returns accumulated result")
-MSpec.register(:exclude, "Coverage.result gives the covered files as a hash with arrays of count or nil")
-MSpec.register(:exclude, "Coverage.result returns results for each mode separately when enabled :all modes")
-MSpec.register(:exclude, "Coverage.result returns results for each mode separately when enabled any mode explicitly")
-MSpec.register(:exclude, "Coverage.result returns the correct results when eval coverage is enabled")
+# We need to respect the eval coverage setting.
MSpec.register(:exclude, "Coverage.result returns the correct results when eval coverage is disabled")
-MSpec.register(:exclude, "Coverage.result clears counters (sets 0 values) when stop is not specified but clear: true specified")
-MSpec.register(:exclude, "Coverage.result does not clear counters when stop is not specified but clear: false specified")
-MSpec.register(:exclude, "Coverage.result does not clear counters when stop: false and clear is not specified")
-MSpec.register(:exclude, "Coverage.result clears counters (sets 0 values) when stop: false and clear: true specified")
-MSpec.register(:exclude, "Coverage.result does not clear counters when stop: false and clear: false specified")
-MSpec.register(:exclude, "Coverage.start measures coverage within eval")
-MSpec.register(:exclude, "Socket.gethostbyaddr using an IPv6 address with an explicit address family raises SocketError when the address is not supported by the family")
diff --git a/spec/ruby/core/binding/irb_spec.rb b/spec/ruby/core/binding/irb_spec.rb
index 25521f0dd7..2607c7ef33 100644
--- a/spec/ruby/core/binding/irb_spec.rb
+++ b/spec/ruby/core/binding/irb_spec.rb
@@ -10,7 +10,7 @@ describe "Binding#irb" do
IO.popen([envs, *ruby_exe, irb_fixture, chdir: dir], "r+") do |pipe|
pipe.puts "a ** 2"
pipe.puts "exit"
- pipe.readlines.map(&:chomp)
+ pipe.readlines.map(&:chomp).reject(&:empty?)
end
end
diff --git a/spec/ruby/core/encoding/inspect_spec.rb b/spec/ruby/core/encoding/inspect_spec.rb
index 9a930b2a77..df96141db9 100644
--- a/spec/ruby/core/encoding/inspect_spec.rb
+++ b/spec/ruby/core/encoding/inspect_spec.rb
@@ -5,9 +5,23 @@ describe "Encoding#inspect" do
Encoding::UTF_8.inspect.should be_an_instance_of(String)
end
- it "returns #<Encoding:name> for a non-dummy encoding named 'name'" do
- Encoding.list.to_a.reject {|e| e.dummy? }.each do |enc|
- enc.inspect.should =~ /#<Encoding:#{enc.name}>/
+ ruby_version_is ""..."3.4" do
+ it "returns #<Encoding:name> for a non-dummy encoding named 'name'" do
+ Encoding.list.to_a.reject {|e| e.dummy? }.each do |enc|
+ enc.inspect.should =~ /#<Encoding:#{enc.name}>/
+ end
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "returns #<Encoding:name> for a non-dummy encoding named 'name'" do
+ Encoding.list.to_a.reject {|e| e.dummy? }.each do |enc|
+ if enc.name == "ASCII-8BIT"
+ enc.inspect.should == "#<Encoding:BINARY (ASCII-8BIT)>"
+ else
+ enc.inspect.should =~ /#<Encoding:#{enc.name}>/
+ end
+ end
end
end
diff --git a/spec/ruby/core/string/index_spec.rb b/spec/ruby/core/string/index_spec.rb
index be79708045..835263a2cd 100644
--- a/spec/ruby/core/string/index_spec.rb
+++ b/spec/ruby/core/string/index_spec.rb
@@ -231,6 +231,17 @@ 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
+
+ string = "blablabla"
+ string.index(/bla/, string.length + 1)
+ $~.should == nil
+ end
+ end
+
it "starts the search at the given offset" do
"blablabla".index(/.{0}/, 5).should == 5
"blablabla".index(/.{1}/, 5).should == 5
diff --git a/spec/ruby/core/warning/element_reference_spec.rb b/spec/ruby/core/warning/element_reference_spec.rb
index 8cb4018c20..c0ed37ef13 100644
--- a/spec/ruby/core/warning/element_reference_spec.rb
+++ b/spec/ruby/core/warning/element_reference_spec.rb
@@ -2,6 +2,10 @@ require_relative '../../spec_helper'
describe "Warning.[]" do
it "returns default values for categories :deprecated and :experimental" do
+ # If any warning options were set on the Ruby that will be executed, then
+ # it's possible this test will fail. In this case we will skip this test.
+ skip if ruby_exe.any? { |opt| opt.start_with?("-W") }
+
ruby_exe('p [Warning[:deprecated], Warning[:experimental]]').chomp.should == "[false, true]"
ruby_exe('p [Warning[:deprecated], Warning[:experimental]]', options: "-w").chomp.should == "[true, true]"
end
diff --git a/spec/ruby/language/break_spec.rb b/spec/ruby/language/break_spec.rb
index 627cb4a071..e725e77e80 100644
--- a/spec/ruby/language/break_spec.rb
+++ b/spec/ruby/language/break_spec.rb
@@ -372,7 +372,7 @@ describe "Executing break from within a block" do
end.should_not raise_error
end
- it "raises LocalJumpError when converted into a proc during a a super call" do
+ it "raises LocalJumpError when converted into a proc during a super call" do
cls1 = Class.new { def foo(&b); b; end }
cls2 = Class.new(cls1) { def foo; super { break 1 }.call; end }
diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c
index bcd3940e34..1a73331386 100644
--- a/spec/ruby/optional/capi/ext/io_spec.c
+++ b/spec/ruby/optional/capi/ext/io_spec.c
@@ -157,7 +157,7 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) {
return ret ? Qtrue : Qfalse;
#else
- UNREACHABLE;
+ UNREACHABLE_RETURN(Qnil);
#endif
}
@@ -174,6 +174,10 @@ VALUE io_spec_rb_io_maybe_wait_writable(VALUE self, VALUE error, VALUE io, VALUE
#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
+
VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p) {
int fd = io_spec_get_fd(io);
#ifndef SET_NON_BLOCKING_FAILS_ALWAYS
@@ -209,7 +213,7 @@ VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE
return INT2NUM(ret);
#else
- UNREACHABLE;
+ UNREACHABLE_RETURN(Qnil);
#endif
}
#endif
diff --git a/string.c b/string.c
index 83bb91f17b..9f7c163a81 100644
--- a/string.c
+++ b/string.c
@@ -3374,7 +3374,7 @@ rb_enc_cr_str_buf_cat(VALUE str, const char *ptr, long len,
incompatible:
rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
- rb_enc_name(str_enc), rb_enc_name(ptr_enc));
+ rb_enc_inspect_name(str_enc), rb_enc_inspect_name(ptr_enc));
UNREACHABLE_RETURN(Qundef);
}
@@ -5854,8 +5854,8 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
if (coderange_scan(p, beg0, str_enc) != ENC_CODERANGE_7BIT ||
coderange_scan(p+end0, len-end0, str_enc) != ENC_CODERANGE_7BIT) {
rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
- rb_enc_name(str_enc),
- rb_enc_name(STR_ENC_GET(repl)));
+ rb_enc_inspect_name(str_enc),
+ rb_enc_inspect_name(STR_ENC_GET(repl)));
}
enc = STR_ENC_GET(repl);
}
@@ -11120,7 +11120,7 @@ str_compat_and_valid(VALUE str, rb_encoding *enc)
rb_encoding *e = STR_ENC_GET(str);
if (cr == ENC_CODERANGE_7BIT ? rb_enc_mbminlen(enc) != 1 : enc != e) {
rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
- rb_enc_name(enc), rb_enc_name(e));
+ rb_enc_inspect_name(enc), rb_enc_inspect_name(e));
}
}
return str;
diff --git a/template/Makefile.in b/template/Makefile.in
index d9a3cbc065..813a727cf9 100644
--- a/template/Makefile.in
+++ b/template/Makefile.in
@@ -663,3 +663,28 @@ yes-test-leaked-globals: yes-test-leaked-globals-precheck
PLATFORM=$(hdrdir)/ruby/$(PLATFORM_DIR).h $(srcdir)/configure.ac \
$(COMMONOBJS) $(LIBRUBY_FOR_LEAKED_GLOBALS:yes=$(LIBRUBY_SO))
$(ACTIONS_ENDGROUP)
+
+test-syntax-suggest-precheck: $(TEST_RUNNABLE)-test-syntax-suggest-precheck
+no-test-syntax-suggest-precheck:
+yes-test-syntax-suggest-precheck: main
+
+test-syntax-suggest-prepare: $(TEST_RUNNABLE)-test-syntax-suggest-prepare
+no-test-syntax-suggest-prepare: no-test-syntax-suggest-precheck
+yes-test-syntax-suggest-prepare: yes-test-syntax-suggest-precheck
+ $(ACTIONS_GROUP)
+ $(XRUBY) -C "$(srcdir)" bin/gem install --no-document \
+ --install-dir .bundle --conservative "rspec:~> 3"
+ $(ACTIONS_ENDGROUP)
+
+RSPECOPTS =
+SYNTAX_SUGGEST_SPECS =
+PREPARE_SYNTAX_SUGGEST = $(TEST_RUNNABLE)-test-syntax-suggest-prepare
+test-syntax-suggest: $(TEST_RUNNABLE)-test-syntax-suggest
+yes-test-syntax-suggest: $(PREPARE_SYNTAX_SUGGEST)
+ $(ACTIONS_GROUP)
+ $(XRUBY) -C $(srcdir) -Ispec/syntax_suggest:spec/lib .bundle/bin/rspec \
+ --require rspec/expectations \
+ --require spec_helper --require formatter_overrides --require spec_coverage \
+ $(RSPECOPTS) spec/syntax_suggest/$(SYNTAX_SUGGEST_SPECS)
+ $(ACTIONS_ENDGROUP)
+no-test-syntax-suggest:
diff --git a/template/prelude.c.tmpl b/template/prelude.c.tmpl
index dc0a143004..e17a75da79 100644
--- a/template/prelude.c.tmpl
+++ b/template/prelude.c.tmpl
@@ -141,37 +141,39 @@ COMPILER_WARNING_POP
#define PRELUDE_NAME(n) rb_usascii_str_new_static(prelude_name##n, sizeof(prelude_name##n)-1)
#define PRELUDE_CODE(n) rb_utf8_str_new_static(prelude_code##n.L0, sizeof(prelude_code##n))
-static rb_ast_t *
-prelude_ast(VALUE name, VALUE code, int line)
+static VALUE
+prelude_ast_value(VALUE name, VALUE code, int line)
{
- rb_ast_t *ast = rb_parser_compile_string_path(rb_parser_new(), name, code, line);
+ rb_ast_t *ast;
+ VALUE ast_value = rb_parser_compile_string_path(rb_parser_new(), name, code, line);
+ ast = rb_ruby_ast_data_get(ast_value);
if (!ast || !ast->body.root) {
if (ast) rb_ast_dispose(ast);
rb_exc_raise(rb_errinfo());
}
- return ast;
+ return ast_value;
}
% end
% if @builtin_count > 0
-#define PRELUDE_AST(n, name_str, start_line) \
+#define PRELUDE_VAST(n, name_str, start_line) \
(((sizeof(prelude_name<%='##'%><%=%>n) - prefix_len - 2) == namelen) && \
(strncmp(prelude_name<%='##'%><%=%>n + prefix_len, feature_name, namelen) == 0) ? \
- prelude_ast((name_str) = PRELUDE_NAME(n), PRELUDE_CODE(n), start_line) : 0)
+ prelude_ast_value((name_str) = PRELUDE_NAME(n), PRELUDE_CODE(n), start_line) : Qnil)
-rb_ast_t *
-rb_builtin_ast(const char *feature_name, VALUE *name_str)
+VALUE
+rb_builtin_ast_value(const char *feature_name, VALUE *name_str)
{
const size_t prefix_len = rb_strlen_lit("<internal:");
size_t namelen = strlen(feature_name);
- rb_ast_t *ast = 0;
+ VALUE ast_value = Qnil;
% @preludes.each_value do |i, prelude, lines, sub, start_line|
% if sub
- if ((ast = PRELUDE_AST(<%=i%><%=%>, *name_str, <%=start_line%>)) != 0) return ast;
+ if (!NIL_P(ast_value = PRELUDE_VAST(<%=i%><%=%>, *name_str, <%=start_line%>))) return ast_value;
% end
% end
- return ast;
+ return ast_value;
}
% end
@@ -196,8 +198,10 @@ prelude_eval(VALUE code, VALUE name, int line)
0, /* int debug_level; */
};
- rb_ast_t *ast = prelude_ast(name, code, line);
- rb_iseq_eval(rb_iseq_new_with_opt(&ast->body, name, name, Qnil, line,
+ rb_ast_t *ast;
+ VALUE ast_value = prelude_ast_value(name, code, line);
+ ast = rb_ruby_ast_data_get(ast_value);
+ rb_iseq_eval(rb_iseq_new_with_opt(ast_value, name, name, Qnil, line,
NULL, 0, ISEQ_TYPE_TOP, &optimization,
Qnil));
rb_ast_dispose(ast);
diff --git a/test/.excludes-prism/TestCall.rb b/test/.excludes-prism/TestCall.rb
deleted file mode 100644
index 969e32ea5a..0000000000
--- a/test/.excludes-prism/TestCall.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-exclude(:test_call_op_asgn_keywords, "https://github.com/ruby/prism/issues/2438")
-exclude(:test_call_op_asgn_keywords_mutable, "https://github.com/ruby/prism/issues/2438")
-exclude(:test_kwsplat_block_order_op_asgn, "https://github.com/ruby/prism/issues/2438")
diff --git a/test/.excludes-prism/TestCoverage.rb b/test/.excludes-prism/TestCoverage.rb
new file mode 100644
index 0000000000..f122d6edbc
--- /dev/null
+++ b/test/.excludes-prism/TestCoverage.rb
@@ -0,0 +1 @@
+exclude(:test_eval, "respect eval coverage setting")
diff --git a/test/.excludes-prism/TestIRB/RubyLexTest.rb b/test/.excludes-prism/TestIRB/RubyLexTest.rb
deleted file mode 100644
index 2274ae62cf..0000000000
--- a/test/.excludes-prism/TestIRB/RubyLexTest.rb
+++ /dev/null
@@ -1 +0,0 @@
-exclude(:test_code_block_open_with_should_continue, "symbol encoding")
diff --git a/test/.excludes-prism/TestISeq.rb b/test/.excludes-prism/TestISeq.rb
index 3768d8fc05..499ae2e53d 100644
--- a/test/.excludes-prism/TestISeq.rb
+++ b/test/.excludes-prism/TestISeq.rb
@@ -1,3 +1,2 @@
-exclude(:test_each_child, "https://github.com/ruby/prism/issues/2660")
-exclude(:test_syntax_error_message, "Assertion checks against specific error format")
-exclude(:test_trace_points, "https://github.com/ruby/prism/issues/2660")
+exclude(:test_each_child, "https://bugs.ruby-lang.org/issues/20479")
+exclude(:test_trace_points, "https://bugs.ruby-lang.org/issues/20479")
diff --git a/test/.excludes-prism/TestM17N.rb b/test/.excludes-prism/TestM17N.rb
index e9e0623689..0367ffa9f2 100644
--- a/test/.excludes-prism/TestM17N.rb
+++ b/test/.excludes-prism/TestM17N.rb
@@ -1,10 +1 @@
-exclude(:test_dynamic_eucjp_regexp, "https://github.com/ruby/prism/issues/2664")
-exclude(:test_dynamic_sjis_regexp, "https://github.com/ruby/prism/issues/2664")
-exclude(:test_dynamic_utf8_regexp, "https://github.com/ruby/prism/issues/2664")
-exclude(:test_regexp_ascii, "https://github.com/ruby/prism/issues/2664")
-exclude(:test_regexp_embed, "https://github.com/ruby/prism/issues/2664")
-exclude(:test_regexp_mixed_unicode, "unknown")
-exclude(:test_regexp_too_short_multibyte_character, "unknown")
-exclude(:test_regexp_unicode, "unknown")
-exclude(:test_regexp_usascii, "unknown")
-exclude(:test_string_mixed_unicode, "unknown")
+exclude(:test_regexp_usascii, "x80 should raise syntax error")
diff --git a/test/.excludes-prism/TestMixedUnicodeEscape.rb b/test/.excludes-prism/TestMixedUnicodeEscape.rb
index 09e3cc168b..753c119d14 100644
--- a/test/.excludes-prism/TestMixedUnicodeEscape.rb
+++ b/test/.excludes-prism/TestMixedUnicodeEscape.rb
@@ -1 +1 @@
-exclude(:test_basic, "unknown")
+exclude(:test_basic, "should raise mixed encoding error")
diff --git a/test/.excludes-prism/TestParse.rb b/test/.excludes-prism/TestParse.rb
index 83af593b15..513a7ed942 100644
--- a/test/.excludes-prism/TestParse.rb
+++ b/test/.excludes-prism/TestParse.rb
@@ -1,28 +1,2 @@
-exclude(:test_dynamic_constant_assignment, "unknown")
-exclude(:test_else_without_rescue, "unknown")
-exclude(:test_error_def_in_argument, "unknown")
-exclude(:test_float, "unknown")
-exclude(:test_global_variable, "unknown")
-exclude(:test_here_document, "unknown")
-exclude(:test_heredoc_unterminated_interpolation, "unknown")
-exclude(:test_invalid_char, "unknown")
-exclude(:test_location_of_invalid_token, "unknown")
-exclude(:test_op_asgn1_with_block, "unknown")
-exclude(:test_parse_string, "unknown")
-exclude(:test_percent, "unknown")
-exclude(:test_question, "unknown")
-exclude(:test_shareable_constant_value_ignored, "unknown")
-exclude(:test_shareable_constant_value_nested, "ractor support")
-exclude(:test_shareable_constant_value_nonliteral, "ractor support")
-exclude(:test_shareable_constant_value_simple, "ractor support")
-exclude(:test_shareable_constant_value_unfrozen, "ractor support")
-exclude(:test_shareable_constant_value_unshareable_literal, "ractor support")
-exclude(:test_string, "unknown")
-exclude(:test_truncated_source_line, "unknown")
-exclude(:test_unassignable, "unknown")
-exclude(:test_unexpected_eof, "unknown")
-exclude(:test_unexpected_token_after_numeric, "unknown")
-exclude(:test_unterminated_regexp_error, "unknown")
-exclude(:test_unused_variable, "missing warning")
-exclude(:test_void_value_in_rhs, "unknown")
-exclude(:test_words, "unknown")
+exclude(:test_truncated_source_line, "truncate error message")
+exclude(:test_void_value_in_rhs, "missing raising error for some void value expressions")
diff --git a/test/.excludes-prism/TestPatternMatching.rb b/test/.excludes-prism/TestPatternMatching.rb
deleted file mode 100644
index cfd0c6bed9..0000000000
--- a/test/.excludes-prism/TestPatternMatching.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-exclude(:test_hash_pattern, "useless literal warning missing")
-exclude(:test_invalid_syntax, "[a:] is disallowed")
diff --git a/test/.excludes-prism/TestRegexp.rb b/test/.excludes-prism/TestRegexp.rb
index 68ad1414a9..5852d870ef 100644
--- a/test/.excludes-prism/TestRegexp.rb
+++ b/test/.excludes-prism/TestRegexp.rb
@@ -1,6 +1,2 @@
-exclude(:test_invalid_escape_error, "unknown")
-exclude(:test_invalid_fragment, "https://github.com/ruby/prism/issues/2664")
-exclude(:test_unescape, "unknown")
-exclude(:test_unicode_age_14_0, "https://github.com/ruby/prism/issues/2664")
-exclude(:test_unicode_age_15_0, "https://github.com/ruby/prism/issues/2664")
-exclude(:test_unicode_age, "https://github.com/ruby/prism/issues/2664")
+exclude(:test_unescape, "unescapes in regexp missing some bytes")
+exclude(:test_match_control_meta_escape, "unescapes in regexp missing some bytes")
diff --git a/test/.excludes-prism/TestRequire.rb b/test/.excludes-prism/TestRequire.rb
index a7f66c5d80..cb35d59c60 100644
--- a/test/.excludes-prism/TestRequire.rb
+++ b/test/.excludes-prism/TestRequire.rb
@@ -1 +1 @@
-exclude(:test_require_nonascii_path_shift_jis, "encoding")
+exclude(:test_require_nonascii_path_shift_jis, "requiring non-ascii paths")
diff --git a/test/.excludes-prism/TestRubyLiteral.rb b/test/.excludes-prism/TestRubyLiteral.rb
index bf5dbcd36a..a25e1c47d9 100644
--- a/test/.excludes-prism/TestRubyLiteral.rb
+++ b/test/.excludes-prism/TestRubyLiteral.rb
@@ -1,6 +1 @@
-exclude(:test_debug_frozen_string_in_array_literal, "unknown")
-exclude(:test_debug_frozen_string, "unknown")
-exclude(:test_dregexp, "https://github.com/ruby/prism/issues/2664")
-exclude(:test_hash_value_omission, "unknown")
-exclude(:test_integer, "unknown")
-exclude(:test_string, "https://github.com/ruby/prism/issues/2331")
+exclude(:test_dregexp, "x80 should raise syntax error")
diff --git a/test/.excludes-prism/TestRubyOptimization.rb b/test/.excludes-prism/TestRubyOptimization.rb
deleted file mode 100644
index df22ca4f71..0000000000
--- a/test/.excludes-prism/TestRubyOptimization.rb
+++ /dev/null
@@ -1 +0,0 @@
-exclude(:test_peephole_string_literal_range, "unknown")
diff --git a/test/.excludes-prism/TestRubyVM.rb b/test/.excludes-prism/TestRubyVM.rb
deleted file mode 100644
index 6d4c3ca6fe..0000000000
--- a/test/.excludes-prism/TestRubyVM.rb
+++ /dev/null
@@ -1 +0,0 @@
-exclude(:test_keep_script_lines, "unknown")
diff --git a/test/.excludes-prism/TestSetTraceFunc.rb b/test/.excludes-prism/TestSetTraceFunc.rb
deleted file mode 100644
index dd0ea3b219..0000000000
--- a/test/.excludes-prism/TestSetTraceFunc.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-exclude(:test_return, "unknown")
-exclude(:test_return2, "unknown")
diff --git a/test/.excludes-prism/TestSyntax.rb b/test/.excludes-prism/TestSyntax.rb
index f8ae776930..0505330b1c 100644
--- a/test/.excludes-prism/TestSyntax.rb
+++ b/test/.excludes-prism/TestSyntax.rb
@@ -1,30 +1,9 @@
-exclude(:test__END___cr, "unknown")
-exclude(:test_anonymous_block_forwarding, "unknown")
-exclude(:test_anonymous_keyword_rest_forwarding, "unknown")
-exclude(:test_anonymous_rest_forwarding, "unknown")
-exclude(:test_argument_forwarding_with_super, "unknown")
-exclude(:test_argument_forwarding, "unknown")
-exclude(:test_brace_after_literal_argument, "unknown")
-exclude(:test_dedented_heredoc_concatenation, "unknown")
-exclude(:test_dedented_heredoc_continued_line, "unknown")
-exclude(:test_dedented_heredoc_invalid_identifer, "unknown")
-exclude(:test_duplicated_when, "unknown")
-exclude(:test_error_message_encoding, "unknown")
-exclude(:test_heredoc_cr, "unknown")
-exclude(:test_heredoc_no_terminator, "unknown")
-exclude(:test_invalid_encoding_symbol, "unknown")
+exclude(:test_dedented_heredoc_continued_line, "heredoc line continuation dedent calculation")
exclude(:test_it, "https://github.com/ruby/prism/issues/2323")
-exclude(:test_keyword_invalid_name, "unknown")
-exclude(:test_keyword_self_reference, "unknown")
-exclude(:test_keywords_specified_and_not_accepted, "unknown")
-exclude(:test_methoddef_endless_command, "unknown")
-exclude(:test_numbered_parameter, "unknown")
-exclude(:test_optional_self_reference, "unknown")
-exclude(:test_safe_call_in_massign_lhs, "unknown")
-exclude(:test_syntax_error_at_newline, "unknown")
-exclude(:test_unassignable, "unknown")
-exclude(:test_unexpected_fraction, "unknown")
-exclude(:test_unterminated_heredoc_cr, "unknown")
-exclude(:test_unterminated_heredoc, "unknown")
-exclude(:test_warn_balanced, "unknown")
-exclude(:test_warn_unreachable, "unknown")
+exclude(:test_numbered_parameter, "should raise syntax error for numbered parameters in inner blocks")
+exclude(:test_unterminated_heredoc_cr, "quoted \r heredoc terminators should not match \r\n")
+exclude(:test_warn_balanced, "missing warning for ** being interpreted as a binary operator")
+
+exclude(:test_duplicated_when, "https://bugs.ruby-lang.org/issues/20401")
+exclude(:test_optional_self_reference, "https://bugs.ruby-lang.org/issues/20478")
+exclude(:test_keyword_self_reference, "https://bugs.ruby-lang.org/issues/20478")
diff --git a/test/.excludes-prism/TestUnicodeEscape.rb b/test/.excludes-prism/TestUnicodeEscape.rb
deleted file mode 100644
index add4911bc2..0000000000
--- a/test/.excludes-prism/TestUnicodeEscape.rb
+++ /dev/null
@@ -1 +0,0 @@
-exclude(:test_fail, "unknown")
diff --git a/test/coverage/test_coverage.rb b/test/coverage/test_coverage.rb
index 16be47b458..4773280cae 100644
--- a/test/coverage/test_coverage.rb
+++ b/test/coverage/test_coverage.rb
@@ -5,22 +5,33 @@ require "tmpdir"
require "envutil"
class TestCoverage < Test::Unit::TestCase
+ # The command-line arguments that we will pass to the ruby subprocess invoked
+ # by assert_in_out_err. In general this is just requiring the coverage
+ # library, but if prism is enabled we want to additionally pass that option
+ # through.
+ ARGV = ["-rcoverage"]
+
+ if RubyVM::InstructionSequence.compile('').to_a[4][:parser] == :prism
+ ARGV << "-W:no-experimental"
+ ARGV << "--parser=prism"
+ end
+
def test_result_without_start
- assert_in_out_err(%w[-rcoverage], <<-"end;", [], /coverage measurement is not enabled/)
+ assert_in_out_err(ARGV, <<-"end;", [], /coverage measurement is not enabled/)
Coverage.result
p :NG
end;
end
def test_peek_result_without_start
- assert_in_out_err(%w[-rcoverage], <<-"end;", [], /coverage measurement is not enabled/)
+ assert_in_out_err(ARGV, <<-"end;", [], /coverage measurement is not enabled/)
Coverage.peek_result
p :NG
end;
end
def test_result_with_nothing
- assert_in_out_err(%w[-rcoverage], <<-"end;", ["{}"], [])
+ assert_in_out_err(ARGV, <<-"end;", ["{}"], [])
Coverage.start
p Coverage.result
end;
@@ -34,7 +45,7 @@ class TestCoverage < Test::Unit::TestCase
end
def test_coverage_running?
- assert_in_out_err(%w[-rcoverage], <<-"end;", ["false", "true", "true", "false"], [])
+ assert_in_out_err(ARGV, <<-"end;", ["false", "true", "true", "false"], [])
p Coverage.running?
Coverage.start
p Coverage.running?
@@ -56,7 +67,7 @@ class TestCoverage < Test::Unit::TestCase
EOS
end
- assert_in_out_err(%w[-rcoverage], <<-"end;", ["[1, 0, nil]", "[1, 1, nil]", "[1, 1, nil]"], [])
+ assert_in_out_err(ARGV, <<-"end;", ["[1, 0, nil]", "[1, 1, nil]", "[1, 1, nil]"], [])
Coverage.start
tmp = Dir.pwd
require tmp + "/test.rb"
@@ -92,7 +103,7 @@ class TestCoverage < Test::Unit::TestCase
exp1 = { "#{tmp}/test.rb" => [1, 0, nil] }.inspect
exp2 = {}.inspect
exp3 = { "#{tmp}/test2.rb" => [1] }.inspect
- assert_in_out_err(%w[-rcoverage], <<-"end;", [exp1, exp2, exp3], [])
+ assert_in_out_err(ARGV, <<-"end;", [exp1, exp2, exp3], [])
Coverage.start
tmp = Dir.pwd
require tmp + "/test.rb"
@@ -124,7 +135,7 @@ class TestCoverage < Test::Unit::TestCase
f.puts "])"
end
- assert_in_out_err(%w[-rcoverage], <<-"end;", ["10003"], [])
+ assert_in_out_err(ARGV, <<-"end;", ["10003"], [])
Coverage.start
tmp = Dir.pwd
require tmp + '/test.rb'
@@ -153,7 +164,7 @@ class TestCoverage < Test::Unit::TestCase
f.puts 'end'
end
- assert_in_out_err(%w[-W0 -rcoverage], <<-"end;", ["[1, 1, 1, 400, nil, nil, nil, nil, nil, nil, nil]"], [], bug13305)
+ assert_in_out_err(["-W0", *ARGV], <<-"end;", ["[1, 1, 1, 400, nil, nil, nil, nil, nil, nil, nil]"], [], bug13305)
Coverage.start(:all)
tmp = Dir.pwd
require tmp + '/test.rb'
@@ -165,7 +176,7 @@ class TestCoverage < Test::Unit::TestCase
end
def test_eval_coverage
- assert_in_out_err(%w[-rcoverage], <<-"end;", ["[1, 1, 1, nil, 0, nil]"], [])
+ assert_in_out_err(ARGV, <<-"end;", ["[1, 1, 1, nil, 0, nil]"], [])
Coverage.start(eval: true, lines: true)
eval(<<-RUBY, TOPLEVEL_BINDING, "test.rb")
@@ -242,7 +253,7 @@ class TestCoverage < Test::Unit::TestCase
Dir.chdir(tmp) {
File.write("test.rb", code)
- assert_in_out_err(%w[-W0 -rcoverage], <<-"end;", stdout, [])
+ assert_in_out_err(["-W0", *ARGV], <<-"end;", stdout, [])
Coverage.start(#{ opt })
tmp = Dir.pwd
require tmp + '/test.rb'
@@ -642,7 +653,7 @@ class TestCoverage < Test::Unit::TestCase
"{:lines=>[0, 1, 1, nil, 0, nil, nil]}",
"{:lines=>[0, 1, 0, nil, 1, nil, nil]}",
]
- assert_in_out_err(%w[-rcoverage], <<-"end;", exp, [])
+ assert_in_out_err(ARGV, <<-"end;", exp, [])
Coverage.start(lines: true)
tmp = Dir.pwd
f = tmp + "/test.rb"
@@ -676,7 +687,7 @@ class TestCoverage < Test::Unit::TestCase
"{:branches=>{[:if, 0, 2, 2, 6, 5]=>{[:then, 1, 3, 4, 3, 8]=>0, [:else, 2, 5, 4, 5, 12]=>1}}}",
"{:branches=>{[:if, 0, 2, 2, 6, 5]=>{[:then, 1, 3, 4, 3, 8]=>0, [:else, 2, 5, 4, 5, 12]=>1}}}",
]
- assert_in_out_err(%w[-rcoverage], <<-"end;", exp, [])
+ assert_in_out_err(ARGV, <<-"end;", exp, [])
Coverage.start(branches: true)
tmp = Dir.pwd
f = tmp + "/test.rb"
@@ -712,7 +723,7 @@ class TestCoverage < Test::Unit::TestCase
"{:methods=>{[Object, :foo, 1, 0, 7, 3]=>1}}",
"{:methods=>{[Object, :foo, 1, 0, 7, 3]=>1}}"
]
- assert_in_out_err(%w[-rcoverage], <<-"end;", exp, [])
+ assert_in_out_err(ARGV, <<-"end;", exp, [])
Coverage.start(methods: true)
tmp = Dir.pwd
f = tmp + "/test.rb"
@@ -748,7 +759,7 @@ class TestCoverage < Test::Unit::TestCase
"{:oneshot_lines=>[5]}",
"{:oneshot_lines=>[]}",
]
- assert_in_out_err(%w[-rcoverage], <<-"end;", exp, [])
+ assert_in_out_err(ARGV, <<-"end;", exp, [])
Coverage.start(oneshot_lines: true)
tmp = Dir.pwd
f = tmp + "/test.rb"
@@ -924,7 +935,7 @@ class TestCoverage < Test::Unit::TestCase
end
def test_coverage_state
- assert_in_out_err(%w[-rcoverage], <<-"end;", [":idle", ":running", ":running", ":idle"], [])
+ assert_in_out_err(ARGV, <<-"end;", [":idle", ":running", ":running", ":idle"], [])
p Coverage.state
Coverage.start
p Coverage.state
@@ -934,7 +945,7 @@ class TestCoverage < Test::Unit::TestCase
p Coverage.state
end;
- assert_in_out_err(%w[-rcoverage], <<-"end;", [":idle", ":suspended", ":running", ":suspended", ":running", ":suspended", ":idle"], [])
+ assert_in_out_err(ARGV, <<-"end;", [":idle", ":suspended", ":running", ":suspended", ":running", ":suspended", ":idle"], [])
p Coverage.state
Coverage.setup
p Coverage.state
@@ -952,14 +963,14 @@ class TestCoverage < Test::Unit::TestCase
end
def test_result_without_resume
- assert_in_out_err(%w[-rcoverage], <<-"end;", ["{}"], [])
+ assert_in_out_err(ARGV, <<-"end;", ["{}"], [])
Coverage.setup
p Coverage.result
end;
end
def test_result_after_suspend
- assert_in_out_err(%w[-rcoverage], <<-"end;", ["{}"], [])
+ assert_in_out_err(ARGV, <<-"end;", ["{}"], [])
Coverage.start
Coverage.suspend
p Coverage.result
@@ -967,21 +978,21 @@ class TestCoverage < Test::Unit::TestCase
end
def test_resume_without_setup
- assert_in_out_err(%w[-rcoverage], <<-"end;", [], /coverage measurement is not set up yet/)
+ assert_in_out_err(ARGV, <<-"end;", [], /coverage measurement is not set up yet/)
Coverage.resume
p :NG
end;
end
def test_suspend_without_setup
- assert_in_out_err(%w[-rcoverage], <<-"end;", [], /coverage measurement is not running/)
+ assert_in_out_err(ARGV, <<-"end;", [], /coverage measurement is not running/)
Coverage.suspend
p :NG
end;
end
def test_double_resume
- assert_in_out_err(%w[-rcoverage], <<-"end;", [], /coverage measurement is already running/)
+ assert_in_out_err(ARGV, <<-"end;", [], /coverage measurement is already running/)
Coverage.start
Coverage.resume
p :NG
@@ -989,7 +1000,7 @@ class TestCoverage < Test::Unit::TestCase
end
def test_double_suspend
- assert_in_out_err(%w[-rcoverage], <<-"end;", [], /coverage measurement is not running/)
+ assert_in_out_err(ARGV, <<-"end;", [], /coverage measurement is not running/)
Coverage.setup
Coverage.suspend
p :NG
diff --git a/test/irb/command/test_custom_command.rb b/test/irb/command/test_custom_command.rb
new file mode 100644
index 0000000000..3a3ad11d5a
--- /dev/null
+++ b/test/irb/command/test_custom_command.rb
@@ -0,0 +1,149 @@
+# frozen_string_literal: true
+require "irb"
+
+require_relative "../helper"
+
+module TestIRB
+ class CustomCommandIntegrationTest < TestIRB::IntegrationTestCase
+ def test_command_registration_can_happen_after_irb_require
+ write_ruby <<~RUBY
+ require "irb"
+ require "irb/command"
+
+ class PrintCommand < IRB::Command::Base
+ category 'CommandTest'
+ description 'print_command'
+ def execute(*)
+ puts "Hello from PrintCommand"
+ end
+ end
+
+ IRB::Command.register(:print!, PrintCommand)
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "print!"
+ type "exit"
+ end
+
+ assert_include(output, "Hello from PrintCommand")
+ end
+
+ def test_command_registration_accepts_string_too
+ write_ruby <<~RUBY
+ require "irb/command"
+
+ class PrintCommand < IRB::Command::Base
+ category 'CommandTest'
+ description 'print_command'
+ def execute(*)
+ puts "Hello from PrintCommand"
+ end
+ end
+
+ IRB::Command.register("print!", PrintCommand)
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "print!"
+ type "exit"
+ end
+
+ assert_include(output, "Hello from PrintCommand")
+ end
+
+ def test_arguments_propagation
+ write_ruby <<~RUBY
+ require "irb/command"
+
+ class PrintArgCommand < IRB::Command::Base
+ category 'CommandTest'
+ description 'print_command_arg'
+ def execute(arg)
+ $nth_execution ||= 0
+ puts "\#{$nth_execution} arg=\#{arg.inspect}"
+ $nth_execution += 1
+ end
+ end
+
+ IRB::Command.register(:print_arg, PrintArgCommand)
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "print_arg"
+ type "print_arg \n"
+ type "print_arg a r g"
+ type "print_arg a r g \n"
+ type "exit"
+ end
+
+ assert_include(output, "0 arg=\"\"")
+ assert_include(output, "1 arg=\"\"")
+ assert_include(output, "2 arg=\"a r g\"")
+ assert_include(output, "3 arg=\"a r g\"")
+ end
+
+ def test_def_extend_command_still_works
+ write_ruby <<~RUBY
+ require "irb"
+
+ class FooBarCommand < IRB::Command::Base
+ category 'FooBarCategory'
+ description 'foobar_description'
+ def execute(*)
+ $nth_execution ||= 1
+ puts "\#{$nth_execution} FooBar executed"
+ $nth_execution += 1
+ end
+ end
+
+ IRB::ExtendCommandBundle.def_extend_command(:foobar, FooBarCommand, nil, [:fbalias, IRB::Command::OVERRIDE_ALL])
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "foobar"
+ type "fbalias"
+ type "help foobar"
+ type "exit"
+ end
+
+ assert_include(output, "1 FooBar executed")
+ assert_include(output, "2 FooBar executed")
+ assert_include(output, "foobar_description")
+ end
+
+ def test_no_meta_command_also_works
+ write_ruby <<~RUBY
+ require "irb/command"
+
+ class NoMetaCommand < IRB::Command::Base
+ def execute(*)
+ puts "This command does not override meta attributes"
+ end
+ end
+
+ IRB::Command.register(:no_meta, NoMetaCommand)
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "no_meta"
+ type "help no_meta"
+ type "exit"
+ end
+
+ assert_include(output, "This command does not override meta attributes")
+ assert_include(output, "No description provided.")
+ assert_not_include(output, "Maybe IRB bug")
+ end
+ end
+end
diff --git a/test/irb/command/test_force_exit.rb b/test/irb/command/test_force_exit.rb
index 9e86c644d6..191a786872 100644
--- a/test/irb/command/test_force_exit.rb
+++ b/test/irb/command/test_force_exit.rb
@@ -47,17 +47,5 @@ module TestIRB
assert_match(/irb\(main\):001> 123/, output)
end
-
- def test_forced_exit_out_of_irb_session
- write_ruby <<~'ruby'
- at_exit { puts 'un' + 'reachable' }
- binding.irb
- exit! # this will call exit! method overrided by command
- ruby
- output = run_ruby_file do
- type "exit"
- end
- assert_not_include(output, 'unreachable')
- end
end
end
diff --git a/test/irb/command/test_help.rb b/test/irb/command/test_help.rb
index c82c43a4c5..b34832b022 100644
--- a/test/irb/command/test_help.rb
+++ b/test/irb/command/test_help.rb
@@ -62,5 +62,14 @@ module TestIRB
assert_match(/\$\s+Alias for `show_source`/, out)
assert_match(/@\s+Alias for `whereami`/, out)
end
+
+ def test_help_lists_helper_methods
+ out = run_ruby_file do
+ type "help"
+ type "exit"
+ end
+
+ assert_match(/Helper methods\s+conf\s+Returns the current IRB context/, out)
+ end
end
end
diff --git a/test/irb/command/test_multi_irb_commands.rb b/test/irb/command/test_multi_irb_commands.rb
new file mode 100644
index 0000000000..e313c0c5d2
--- /dev/null
+++ b/test/irb/command/test_multi_irb_commands.rb
@@ -0,0 +1,50 @@
+require "tempfile"
+require_relative "../helper"
+
+module TestIRB
+ class MultiIRBTest < IntegrationTestCase
+ def setup
+ super
+
+ write_ruby <<~'RUBY'
+ binding.irb
+ RUBY
+ end
+
+ def test_jobs_command_with_print_deprecated_warning
+ out = run_ruby_file do
+ type "jobs"
+ type "exit"
+ end
+
+ assert_match(/Multi-irb commands are deprecated and will be removed in IRB 2\.0\.0\. Please use workspace commands instead\./, out)
+ assert_match(%r|If you have any use case for multi-irb, please leave a comment at https://github.com/ruby/irb/issues/653|, out)
+ assert_match(/#0->irb on main \(#<Thread:0x.+ run>: running\)/, out)
+ end
+
+ def test_irb_jobs_and_kill_commands
+ out = run_ruby_file do
+ type "irb"
+ type "jobs"
+ type "kill 1"
+ type "exit"
+ end
+
+ assert_match(/#0->irb on main \(#<Thread:0x.+ sleep_forever>: stop\)/, out)
+ assert_match(/#1->irb#1 on main \(#<Thread:0x.+ run>: running\)/, out)
+ end
+
+ def test_irb_fg_jobs_and_kill_commands
+ out = run_ruby_file do
+ type "irb"
+ type "fg 0"
+ type "jobs"
+ type "kill 1"
+ type "exit"
+ end
+
+ assert_match(/#0->irb on main \(#<Thread:0x.+ run>: running\)/, out)
+ assert_match(/#1->irb#1 on main \(#<Thread:0x.+ sleep_forever>: stop\)/, out)
+ end
+ end
+end
diff --git a/test/irb/helper.rb b/test/irb/helper.rb
index 1614b42adb..acaf6277f3 100644
--- a/test/irb/helper.rb
+++ b/test/irb/helper.rb
@@ -121,7 +121,9 @@ module TestIRB
@envs["XDG_CONFIG_HOME"] ||= tmp_dir
@envs["IRBRC"] = nil unless @envs.key?("IRBRC")
- PTY.spawn(@envs.merge("TERM" => "dumb"), *cmd) do |read, write, pid|
+ envs_for_spawn = @envs.merge('TERM' => 'dumb', 'TEST_IRB_FORCE_INTERACTIVE' => 'true')
+
+ PTY.spawn(envs_for_spawn, *cmd) do |read, write, pid|
Timeout.timeout(TIMEOUT_SEC) do
while line = safe_gets(read)
lines << line
@@ -196,7 +198,7 @@ module TestIRB
end
def write_ruby(program)
- @ruby_file = Tempfile.create(%w{irb- .rb})
+ @ruby_file = Tempfile.create(%w{irbtest- .rb})
@tmpfiles << @ruby_file
@ruby_file.write(program)
@ruby_file.close
diff --git a/test/irb/test_color.rb b/test/irb/test_color.rb
index 72e036eab7..9d78f5233e 100644
--- a/test/irb/test_color.rb
+++ b/test/irb/test_color.rb
@@ -99,7 +99,7 @@ module TestIRB
"foo %i[bar]" => "foo #{YELLOW}%i[#{CLEAR}#{YELLOW}bar#{CLEAR}#{YELLOW}]#{CLEAR}",
"foo :@bar, baz, :@@qux, :$quux" => "foo #{YELLOW}:#{CLEAR}#{YELLOW}@bar#{CLEAR}, baz, #{YELLOW}:#{CLEAR}#{YELLOW}@@qux#{CLEAR}, #{YELLOW}:#{CLEAR}#{YELLOW}$quux#{CLEAR}",
"`echo`" => "#{RED}#{BOLD}`#{CLEAR}#{RED}echo#{CLEAR}#{RED}#{BOLD}`#{CLEAR}",
- "\t" => "\t", # not ^I
+ "\t" => Reline::Unicode.escape_for_print("\t") == ' ' ? ' ' : "\t", # not ^I
"foo(*%W(bar))" => "foo(*#{RED}#{BOLD}%W(#{CLEAR}#{RED}bar#{CLEAR}#{RED}#{BOLD})#{CLEAR})",
"$stdout" => "#{GREEN}#{BOLD}$stdout#{CLEAR}",
"__END__" => "#{GREEN}__END__#{CLEAR}",
diff --git a/test/irb/test_command.rb b/test/irb/test_command.rb
index 03fdd37855..8cb8928adb 100644
--- a/test/irb/test_command.rb
+++ b/test/irb/test_command.rb
@@ -210,76 +210,6 @@ module TestIRB
end
end
- class CustomCommandTestCase < CommandTestCase
- def setup
- @commands_backup = IRB::Command.commands
- IRB::ExtendCommandBundle.class_variable_set(:@@command_override_policies, nil)
- end
-
- def teardown
- IRB::ExtendCommandBundle.class_variable_set(:@@command_override_policies, nil)
- IRB::Command.instance_variable_set(:@commands, @commands_backup)
- end
- end
-
- class CommandArgTest < CustomCommandTestCase
- class PrintArgCommand < IRB::Command::Base
- category 'CommandTest'
- description 'print_command_arg'
- def execute(arg)
- puts "arg=#{arg.inspect}"
- end
- end
-
- def test_arg
- IRB::Command._register_with_aliases(:print_arg, PrintArgCommand, [:pa, IRB::ExtendCommandBundle::OVERRIDE_ALL])
- out, err = execute_lines("print_arg\n")
- assert_empty err
- assert_include(out, 'arg=""')
-
- out, err = execute_lines("print_arg \n")
- assert_empty err
- assert_include(out, 'arg=""')
-
- out, err = execute_lines("print_arg a r g\n")
- assert_empty err
- assert_include(out, 'arg="a r g"')
-
- out, err = execute_lines("print_arg a r g \n")
- assert_empty err
- assert_include(out, 'arg="a r g"')
-
- out, err = execute_lines("pa a r g \n")
- assert_empty err
- assert_include(out, 'arg="a r g"')
- end
- end
-
- class ExtendCommandBundleCompatibilityTest < CustomCommandTestCase
- class FooBarCommand < IRB::Command::Base
- category 'FooBarCategory'
- description 'foobar_description'
- def execute(_arg)
- puts "FooBar executed"
- end
- end
-
- def test_def_extend_command
- IRB::Command._register_with_aliases(:foobar, FooBarCommand, [:fbalias, IRB::ExtendCommandBundle::OVERRIDE_ALL])
- out, err = execute_lines("foobar\n")
- assert_empty err
- assert_include(out, "FooBar executed")
-
- out, err = execute_lines("fbalias\n")
- assert_empty err
- assert_include(out, "FooBar executed")
-
- out, err = execute_lines("show_cmds\n")
- assert_include(out, "FooBarCategory")
- assert_include(out, "foobar_description")
- end
- end
-
class MeasureTest < CommandTestCase
def test_measure
conf = {
@@ -555,12 +485,11 @@ module TestIRB
class CwwsTest < WorkspaceCommandTestCase
def test_cwws_returns_the_current_workspace_object
out, err = execute_lines(
- "cwws",
- "self.class"
+ "cwws"
)
assert_empty err
- assert_include(out, self.class.name)
+ assert_include(out, "Current workspace: #{self}")
end
end
@@ -626,7 +555,7 @@ module TestIRB
"pushws Foo.new\n",
"popws\n",
"cwws\n",
- "_.class",
+ "self.class",
)
assert_empty err
assert_include(out, "=> #{self.class}")
@@ -646,20 +575,19 @@ module TestIRB
out, err = execute_lines(
"chws #{self.class}::Foo.new\n",
"cwws\n",
- "_.class",
+ "self.class\n"
)
assert_empty err
+ assert_include(out, "Current workspace: #<#{self.class.name}::Foo")
assert_include(out, "=> #{self.class}::Foo")
end
def test_chws_does_nothing_when_receiving_no_argument
out, err = execute_lines(
"chws\n",
- "cwws\n",
- "_.class",
)
assert_empty err
- assert_include(out, "=> #{self.class}")
+ assert_include(out, "Current workspace: #{self}")
end
end
diff --git a/test/irb/test_context.rb b/test/irb/test_context.rb
index aff4b5b67c..cd3f2c8f62 100644
--- a/test/irb/test_context.rb
+++ b/test/irb/test_context.rb
@@ -662,6 +662,14 @@ module TestIRB
assert_equal("irb(!ArgumentError)>", irb.send(:format_prompt, 'irb(%M)>', nil, 1, 1))
end
+ def test_prompt_format
+ main = 'main'
+ irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new)
+ assert_equal('%% main %m %main %%m >', irb.send(:format_prompt, '%%%% %m %%m %%%m %%%%m %l', '>', 1, 1))
+ assert_equal('42,%i, 42,%3i,042,%03i', irb.send(:format_prompt, '%i,%%i,%3i,%%3i,%03i,%%03i', nil, 42, 1))
+ assert_equal('42,%n, 42,%3n,042,%03n', irb.send(:format_prompt, '%n,%%n,%3n,%%3n,%03n,%%03n', nil, 1, 42))
+ end
+
def test_lineno
input = TestInputMethod.new([
"\n",
diff --git a/test/irb/test_debugger_integration.rb b/test/irb/test_debugger_integration.rb
index 839a0d43f0..8b1bddea17 100644
--- a/test/irb/test_debugger_integration.rb
+++ b/test/irb/test_debugger_integration.rb
@@ -67,6 +67,22 @@ module TestIRB
assert_match(/IRB is already running with a debug session/, output)
end
+ def test_debug_command_can_only_be_called_from_binding_irb
+ write_ruby <<~'ruby'
+ require "irb"
+ # trick test framework
+ puts "binding.irb"
+ IRB.start
+ ruby
+
+ output = run_ruby_file do
+ type "debug"
+ type "exit"
+ end
+
+ assert_include(output, "Debugging commands are only available when IRB is started with binding.irb")
+ end
+
def test_next
write_ruby <<~'ruby'
binding.irb
@@ -244,28 +260,46 @@ module TestIRB
def test_exit
write_ruby <<~'RUBY'
binding.irb
- puts "hello"
+ puts "he" + "llo"
RUBY
output = run_ruby_file do
- type "next"
+ type "debug"
type "exit"
end
- assert_match(/irb\(main\):001> next/, output)
+ assert_match(/irb:rdbg\(main\):002>/, output)
+ assert_match(/hello/, output)
+ end
+
+ def test_force_exit
+ write_ruby <<~'RUBY'
+ binding.irb
+ puts "he" + "llo"
+ RUBY
+
+ output = run_ruby_file do
+ type "debug"
+ type "exit!"
+ end
+
+ assert_match(/irb:rdbg\(main\):002>/, output)
+ assert_not_match(/hello/, output)
end
def test_quit
write_ruby <<~'RUBY'
binding.irb
+ puts "he" + "llo"
RUBY
output = run_ruby_file do
- type "next"
+ type "debug"
type "quit!"
end
- assert_match(/irb\(main\):001> next/, output)
+ assert_match(/irb:rdbg\(main\):002>/, output)
+ assert_not_match(/hello/, output)
end
def test_prompt_line_number_continues
diff --git a/test/irb/test_helper_method.rb b/test/irb/test_helper_method.rb
new file mode 100644
index 0000000000..291278c16a
--- /dev/null
+++ b/test/irb/test_helper_method.rb
@@ -0,0 +1,134 @@
+# frozen_string_literal: true
+require "irb"
+
+require_relative "helper"
+
+module TestIRB
+ class HelperMethodTestCase < TestCase
+ def setup
+ $VERBOSE = nil
+ @verbosity = $VERBOSE
+ save_encodings
+ IRB.instance_variable_get(:@CONF).clear
+ end
+
+ def teardown
+ $VERBOSE = @verbosity
+ restore_encodings
+ end
+
+ def execute_lines(*lines, conf: {}, main: self, irb_path: nil)
+ IRB.init_config(nil)
+ IRB.conf[:VERBOSE] = false
+ IRB.conf[:PROMPT_MODE] = :SIMPLE
+ IRB.conf.merge!(conf)
+ input = TestInputMethod.new(lines)
+ irb = IRB::Irb.new(IRB::WorkSpace.new(main), input)
+ irb.context.return_format = "=> %s\n"
+ irb.context.irb_path = irb_path if irb_path
+ IRB.conf[:MAIN_CONTEXT] = irb.context
+ IRB.conf[:USE_PAGER] = false
+ capture_output do
+ irb.eval_input
+ end
+ end
+ end
+
+ module TestHelperMethod
+ class ConfTest < HelperMethodTestCase
+ def test_conf_returns_the_context_object
+ out, err = execute_lines("conf.ap_name")
+
+ assert_empty err
+ assert_include out, "=> \"irb\""
+ end
+ end
+ end
+
+ class HelperMethodIntegrationTest < IntegrationTestCase
+ def test_arguments_propogation
+ write_ruby <<~RUBY
+ require "irb/helper_method"
+
+ class MyHelper < IRB::HelperMethod::Base
+ description "This is a test helper"
+
+ def execute(
+ required_arg, optional_arg = nil, *splat_arg, required_keyword_arg:,
+ optional_keyword_arg: nil, **double_splat_arg, &block_arg
+ )
+ puts [required_arg, optional_arg, splat_arg, required_keyword_arg, optional_keyword_arg, double_splat_arg, block_arg.call].to_s
+ end
+ end
+
+ IRB::HelperMethod.register(:my_helper, MyHelper)
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type <<~INPUT
+ my_helper(
+ "required", "optional", "splat", required_keyword_arg: "required",
+ optional_keyword_arg: "optional", a: 1, b: 2
+ ) { "block" }
+ INPUT
+ type "exit"
+ end
+
+ assert_include(output, '["required", "optional", ["splat"], "required", "optional", {:a=>1, :b=>2}, "block"]')
+ end
+
+ def test_helper_method_injection_can_happen_after_irb_require
+ write_ruby <<~RUBY
+ require "irb"
+
+ class MyHelper < IRB::HelperMethod::Base
+ description "This is a test helper"
+
+ def execute
+ puts "Hello from MyHelper"
+ end
+ end
+
+ IRB::HelperMethod.register(:my_helper, MyHelper)
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "my_helper"
+ type "exit"
+ end
+
+ assert_include(output, 'Hello from MyHelper')
+ end
+
+ def test_helper_method_instances_are_memoized
+ write_ruby <<~RUBY
+ require "irb/helper_method"
+
+ class MyHelper < IRB::HelperMethod::Base
+ description "This is a test helper"
+
+ def execute(val)
+ @val ||= val
+ end
+ end
+
+ IRB::HelperMethod.register(:my_helper, MyHelper)
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "my_helper(100)"
+ type "my_helper(200)"
+ type "exit"
+ end
+
+ assert_include(output, '=> 100')
+ assert_not_include(output, '=> 200')
+ end
+ end
+end
diff --git a/test/irb/test_init.rb b/test/irb/test_init.rb
index f11d7398c8..3207c2898b 100644
--- a/test/irb/test_init.rb
+++ b/test/irb/test_init.rb
@@ -268,15 +268,95 @@ module TestIRB
end
end
+ class ConfigValidationTest < TestCase
+ def setup
+ @original_home = ENV["HOME"]
+ @original_irbrc = ENV["IRBRC"]
+ # To prevent the test from using the user's .irbrc file
+ ENV["HOME"] = @home = Dir.mktmpdir
+ IRB.instance_variable_set(:@existing_rc_name_generators, nil)
+ super
+ end
+
+ def teardown
+ super
+ ENV["IRBRC"] = @original_irbrc
+ ENV["HOME"] = @original_home
+ File.unlink(@irbrc)
+ Dir.rmdir(@home)
+ end
+
+ def test_irb_name_converts_non_string_values_to_string
+ assert_no_irb_validation_error(<<~'RUBY')
+ IRB.conf[:IRB_NAME] = :foo
+ RUBY
+
+ assert_equal "foo", IRB.conf[:IRB_NAME]
+ end
+
+ def test_irb_rc_name_only_takes_callable_objects
+ assert_irb_validation_error(<<~'RUBY', "IRB.conf[:IRB_RC] should be a callable object. Got :foo.")
+ IRB.conf[:IRB_RC] = :foo
+ RUBY
+ end
+
+ def test_back_trace_limit_only_accepts_integers
+ assert_irb_validation_error(<<~'RUBY', "IRB.conf[:BACK_TRACE_LIMIT] should be an integer. Got \"foo\".")
+ IRB.conf[:BACK_TRACE_LIMIT] = "foo"
+ RUBY
+ end
+
+ def test_prompt_only_accepts_hash
+ assert_irb_validation_error(<<~'RUBY', "IRB.conf[:PROMPT] should be a Hash. Got \"foo\".")
+ IRB.conf[:PROMPT] = "foo"
+ RUBY
+ end
+
+ def test_eval_history_only_accepts_integers
+ assert_irb_validation_error(<<~'RUBY', "IRB.conf[:EVAL_HISTORY] should be an integer. Got \"foo\".")
+ IRB.conf[:EVAL_HISTORY] = "foo"
+ RUBY
+ end
+
+ private
+
+ def assert_irb_validation_error(rc_content, error_message)
+ write_rc rc_content
+
+ assert_raise_with_message(TypeError, error_message) do
+ IRB.setup(__FILE__)
+ end
+ end
+
+ def assert_no_irb_validation_error(rc_content)
+ write_rc rc_content
+
+ assert_nothing_raised do
+ IRB.setup(__FILE__)
+ end
+ end
+
+ def write_rc(content)
+ @irbrc = Tempfile.new('irbrc')
+ @irbrc.write(content)
+ @irbrc.close
+ ENV['IRBRC'] = @irbrc.path
+ end
+ end
+
class InitIntegrationTest < IntegrationTestCase
- def test_load_error_in_rc_file_is_warned
- write_rc <<~'IRBRC'
- require "file_that_does_not_exist"
- IRBRC
+ def setup
+ super
write_ruby <<~'RUBY'
binding.irb
RUBY
+ end
+
+ def test_load_error_in_rc_file_is_warned
+ write_rc <<~'IRBRC'
+ require "file_that_does_not_exist"
+ IRBRC
output = run_ruby_file do
type "'foobar'"
@@ -293,10 +373,6 @@ module TestIRB
raise "I'm an error"
IRBRC
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
output = run_ruby_file do
type "'foobar'"
type "exit"
diff --git a/test/irb/test_irb.rb b/test/irb/test_irb.rb
index 84b9ee3644..28be744088 100644
--- a/test/irb/test_irb.rb
+++ b/test/irb/test_irb.rb
@@ -125,6 +125,26 @@ module TestIRB
end
end
+ class NestedBindingIrbTest < IntegrationTestCase
+ def test_current_context_restore
+ write_ruby <<~'RUBY'
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type '$ctx = IRB.CurrentContext'
+ type 'binding.irb'
+ type 'p context_changed: IRB.CurrentContext != $ctx'
+ type 'exit'
+ type 'p context_restored: IRB.CurrentContext == $ctx'
+ type 'exit'
+ end
+
+ assert_include output, '{:context_changed=>true}'
+ assert_include output, '{:context_restored=>true}'
+ end
+ end
+
class IrbIOConfigurationTest < TestCase
Row = Struct.new(:content, :current_line_spaces, :new_line_spaces, :indent_level)
@@ -803,4 +823,95 @@ module TestIRB
IRB::Irb.new(workspace, TestInputMethod.new)
end
end
+
+ class BacktraceFilteringTest < TestIRB::IntegrationTestCase
+ def test_backtrace_filtering
+ write_ruby <<~'RUBY'
+ def foo
+ raise "error"
+ end
+
+ def bar
+ foo
+ end
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "bar"
+ type "exit"
+ end
+
+ assert_match(/irbtest-.*\.rb:2:in (`|'Object#)foo': error \(RuntimeError\)/, output)
+ frame_traces = output.split("\n").select { |line| line.strip.match?(/from /) }.map(&:strip)
+
+ expected_traces = if RUBY_VERSION >= "3.3.0"
+ [
+ /from .*\/irbtest-.*.rb:6:in (`|'Object#)bar'/,
+ /from .*\/irbtest-.*.rb\(irb\):1:in [`']<main>'/,
+ /from <internal:kernel>:\d+:in (`|'Kernel#)loop'/,
+ /from <internal:prelude>:\d+:in (`|'Binding#)irb'/,
+ /from .*\/irbtest-.*.rb:9:in [`']<main>'/
+ ]
+ else
+ [
+ /from .*\/irbtest-.*.rb:6:in (`|'Object#)bar'/,
+ /from .*\/irbtest-.*.rb\(irb\):1:in [`']<main>'/,
+ /from <internal:prelude>:\d+:in (`|'Binding#)irb'/,
+ /from .*\/irbtest-.*.rb:9:in [`']<main>'/
+ ]
+ end
+
+ expected_traces.reverse! if RUBY_VERSION < "3.0.0"
+
+ expected_traces.each_with_index do |expected_trace, index|
+ assert_match(expected_trace, frame_traces[index])
+ end
+ end
+
+ def test_backtrace_filtering_with_backtrace_filter
+ write_rc <<~'RUBY'
+ class TestBacktraceFilter
+ def self.call(backtrace)
+ backtrace.reject { |line| line.include?("internal") }
+ end
+ end
+
+ IRB.conf[:BACKTRACE_FILTER] = TestBacktraceFilter
+ RUBY
+
+ write_ruby <<~'RUBY'
+ def foo
+ raise "error"
+ end
+
+ def bar
+ foo
+ end
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "bar"
+ type "exit"
+ end
+
+ assert_match(/irbtest-.*\.rb:2:in (`|'Object#)foo': error \(RuntimeError\)/, output)
+ frame_traces = output.split("\n").select { |line| line.strip.match?(/from /) }.map(&:strip)
+
+ expected_traces = [
+ /from .*\/irbtest-.*.rb:6:in (`|'Object#)bar'/,
+ /from .*\/irbtest-.*.rb\(irb\):1:in [`']<main>'/,
+ /from .*\/irbtest-.*.rb:9:in [`']<main>'/
+ ]
+
+ expected_traces.reverse! if RUBY_VERSION < "3.0.0"
+
+ expected_traces.each_with_index do |expected_trace, index|
+ assert_match(expected_trace, frame_traces[index])
+ end
+ end
+ end
end
diff --git a/test/net/http/test_https.rb b/test/net/http/test_https.rb
index 6b3171d265..cf297f3755 100644
--- a/test/net/http/test_https.rb
+++ b/test/net/http/test_https.rb
@@ -168,6 +168,7 @@ class TestNetHTTPS < Test::Unit::TestCase
# 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')
omit if OpenSSL::OPENSSL_LIBRARY_VERSION.include?('OpenSSL 3.2.')
+ omit if OpenSSL::OPENSSL_LIBRARY_VERSION.include?('OpenSSL 3.3.')
http = Net::HTTP.new(HOST, config("port"))
http.use_ssl = true
diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb
index b798b897b4..17f73e4433 100644
--- a/test/objspace/test_objspace.rb
+++ b/test/objspace/test_objspace.rb
@@ -416,7 +416,7 @@ class TestObjSpace < Test::Unit::TestCase
assert_equal('true', ObjectSpace.dump(true))
assert_equal('false', ObjectSpace.dump(false))
assert_equal('0', ObjectSpace.dump(0))
- assert_equal('{"type":"SYMBOL", "value":"foo"}', ObjectSpace.dump(:foo))
+ assert_equal('{"type":"SYMBOL", "value":"test_dump_special_consts"}', ObjectSpace.dump(:test_dump_special_consts))
end
def test_dump_singleton_class
diff --git a/test/objspace/test_ractor.rb b/test/objspace/test_ractor.rb
index b7008ea731..4901eeae2e 100644
--- a/test/objspace/test_ractor.rb
+++ b/test/objspace/test_ractor.rb
@@ -1,17 +1,17 @@
require "test/unit"
class TestObjSpaceRactor < Test::Unit::TestCase
- def test_tracing_does_not_crash
- assert_ractor(<<~RUBY, require: 'objspace')
- ObjectSpace.trace_object_allocations do
- r = Ractor.new do
- obj = 'a' * 1024
- Ractor.yield obj
- end
+ def test_tracing_does_not_crash
+ assert_ractor(<<~RUBY, require: 'objspace')
+ ObjectSpace.trace_object_allocations do
+ r = Ractor.new do
+ obj = 'a' * 1024
+ Ractor.yield obj
+ end
- r.take
- r.take
- end
- RUBY
- end
+ r.take
+ r.take
+ end
+ RUBY
+ end
end
diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb
index 8faa570648..41885fd59b 100644
--- a/test/openssl/test_cipher.rb
+++ b/test/openssl/test_cipher.rb
@@ -331,6 +331,22 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
assert_equal tag1, tag2
end
+ def test_aes_keywrap_pad
+ # RFC 5649 Section 6; The second example
+ kek = ["5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"].pack("H*")
+ key = ["466f7250617369"].pack("H*")
+ wrap = ["afbeb0f07dfbf5419200f2ccb50bb24f"].pack("H*")
+
+ begin
+ cipher = OpenSSL::Cipher.new("id-aes192-wrap-pad").encrypt
+ rescue OpenSSL::Cipher::CipherError, RuntimeError
+ omit "id-aes192-wrap-pad is not supported: #$!"
+ end
+ cipher.key = kek
+ ct = cipher.update(key) << cipher.final
+ assert_equal wrap, ct
+ end
+
def test_non_aead_cipher_set_auth_data
assert_raise(OpenSSL::Cipher::CipherError) {
cipher = OpenSSL::Cipher.new("aes-128-cfb").encrypt
diff --git a/test/openssl/test_digest.rb b/test/openssl/test_digest.rb
index b0b5b9bed1..988330e405 100644
--- a/test/openssl/test_digest.rb
+++ b/test/openssl/test_digest.rb
@@ -88,7 +88,7 @@ class OpenSSL::TestDigest < OpenSSL::TestCase
end
def test_sha512_truncate
- pend "SHA512_224 is not implemented" unless digest_available?('SHA512-224')
+ pend "SHA512_224 is not implemented" unless digest_available?('sha512-224')
sha512_224_a = "d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327"
sha512_256_a = "455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8"
@@ -100,7 +100,7 @@ class OpenSSL::TestDigest < OpenSSL::TestCase
end
def test_sha3
- pend "SHA3 is not implemented" unless digest_available?('SHA3-224')
+ pend "SHA3 is not implemented" unless digest_available?('sha3-224')
s224 = '6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7'
s256 = 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a'
s384 = '0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004'
@@ -126,6 +126,15 @@ class OpenSSL::TestDigest < OpenSSL::TestCase
end
end
+ def test_digests
+ digests = OpenSSL::Digest.digests
+ assert_kind_of Array, digests
+ assert_include digests, "md5"
+ assert_include digests, "sha1"
+ assert_include digests, "sha256"
+ assert_include digests, "sha512"
+ end
+
private
def check_digest(oid)
@@ -138,11 +147,8 @@ class OpenSSL::TestDigest < OpenSSL::TestCase
end
def digest_available?(name)
- begin
- OpenSSL::Digest.new(name)
- rescue RuntimeError
- false
- end
+ @digests ||= OpenSSL::Digest.digests
+ @digests.include?(name)
end
end
diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb
index b616883925..66e36a7ab4 100644
--- a/test/openssl/test_pair.rb
+++ b/test/openssl/test_pair.rb
@@ -250,12 +250,17 @@ module OpenSSL::TestPairM
buf = +"garbage"
assert_equal :wait_readable, s2.read_nonblock(100, buf, exception: false)
- assert_equal "", buf
+ assert_equal "garbage", buf
s1.close
buf = +"garbage"
- assert_equal nil, s2.read(100, buf)
+ assert_nil s2.read(100, buf)
assert_equal "", buf
+
+ buf = +"garbage"
+ ret = s2.read(0, buf)
+ assert_same buf, ret
+ assert_equal "", ret
}
end
diff --git a/test/openssl/test_pkcs7.rb b/test/openssl/test_pkcs7.rb
index ba8b93d034..c049ed444a 100644
--- a/test/openssl/test_pkcs7.rb
+++ b/test/openssl/test_pkcs7.rb
@@ -155,6 +155,21 @@ class OpenSSL::TestPKCS7 < OpenSSL::TestCase
assert_equal(data, p7.decrypt(@rsa1024))
end
+ def test_empty_signed_data_ruby_bug_19974
+ data = "-----BEGIN PKCS7-----\nMAsGCSqGSIb3DQEHAg==\n-----END PKCS7-----\n"
+ assert_raise(ArgumentError) { OpenSSL::PKCS7.new(data) }
+
+ data = <<END
+MIME-Version: 1.0
+Content-Disposition: attachment; filename="smime.p7m"
+Content-Type: application/x-pkcs7-mime; smime-type=signed-data; name="smime.p7m"
+Content-Transfer-Encoding: base64
+
+#{data}
+END
+ assert_raise(OpenSSL::PKCS7::PKCS7Error) { OpenSSL::PKCS7.read_smime(data) }
+ end
+
def test_graceful_parsing_failure #[ruby-core:43250]
contents = File.read(__FILE__)
assert_raise(ArgumentError) { OpenSSL::PKCS7.new(contents) }
@@ -212,6 +227,12 @@ END
assert_equal(p7.to_der, OpenSSL::PKCS7.read_smime(smime).to_der)
end
+ def test_to_text
+ p7 = OpenSSL::PKCS7.new
+ p7.type = "signed"
+ assert_match(/signed/, p7.to_text)
+ end
+
def test_degenerate_pkcs7
ca_cert_pem = <<END
-----BEGIN CERTIFICATE-----
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index 66d63a981d..1471b0cb36 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -117,6 +117,30 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
}
end
+ def test_socket_close_write
+ server_proc = proc do |ctx, ssl|
+ message = ssl.read
+ ssl.write(message)
+ ssl.close_write
+ ensure
+ ssl.close
+ end
+
+ start_server(server_proc: server_proc) do |port|
+ ctx = OpenSSL::SSL::SSLContext.new
+ ssl = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port, context: ctx)
+ ssl.sync_close = true
+ ssl.connect
+
+ message = "abc"*1024
+ ssl.write message
+ ssl.close_write
+ assert_equal message, ssl.read
+ ensure
+ ssl&.close
+ end
+ end
+
def test_add_certificate
ctx_proc = -> ctx {
# Unset values set by start_server
diff --git a/test/openssl/test_ts.rb b/test/openssl/test_ts.rb
index 7cb1a1fe8e..ac0469ad56 100644
--- a/test/openssl/test_ts.rb
+++ b/test/openssl/test_ts.rb
@@ -323,6 +323,8 @@ _end_of_pem_
resp = fac.create_timestamp(ee_key, ts_cert_ee, req)
assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status)
assert_equal("1.2.3.4.6", resp.token_info.policy_id)
+
+ assert_match(/1\.2\.3\.4\.6/, resp.to_text)
end
def test_response_bad_purpose
diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb
index ff17c41163..b98754b8c8 100644
--- a/test/openssl/test_x509req.rb
+++ b/test/openssl/test_x509req.rb
@@ -39,11 +39,6 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
assert_equal(0, req.version)
req = OpenSSL::X509::Request.new(req.to_der)
assert_equal(0, req.version)
-
- req = issue_csr(1, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
- assert_equal(1, req.version)
- req = OpenSSL::X509::Request.new(req.to_der)
- assert_equal(1, req.version)
end
def test_subject
@@ -106,7 +101,7 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
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.version = 1
+ 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
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index 679f6ed0a2..3670b90dd7 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -99,7 +99,7 @@ module Prism
)
assert_errors expected, "BEGIN { 1 + }", [
- ["expected an expression after the operator", 10..11],
+ ["unexpected '}'; expected an expression after the operator", 12..13],
["unexpected '}', assuming it is closing the parent 'BEGIN' block", 12..13]
]
end
@@ -117,25 +117,25 @@ module Prism
def test_unterminated_i_list
assert_errors expression("%i["), "%i[", [
- ["expected a closing delimiter for the `%i` list", 0..3]
+ ["unterminated list; expected a closing delimiter for the `%i`", 0..3]
]
end
def test_unterminated_w_list
assert_errors expression("%w["), "%w[", [
- ["expected a closing delimiter for the `%w` list", 0..3]
+ ["unterminated list; expected a closing delimiter for the `%w`", 0..3]
]
end
def test_unterminated_W_list
assert_errors expression("%W["), "%W[", [
- ["expected a closing delimiter for the `%W` list", 0..3]
+ ["unterminated list; expected a closing delimiter for the `%W`", 0..3]
]
end
def test_unterminated_regular_expression
assert_errors expression("/hello"), "/hello", [
- ["expected a closing delimiter for the regular expression", 0..1]
+ ["unterminated regexp meets end of file; expected a closing delimiter", 0..1]
]
end
@@ -143,7 +143,7 @@ module Prism
source = "<<-END + /b\nEND\n"
assert_errors expression(source), source, [
- ["expected a closing delimiter for the regular expression", 9..10]
+ ["unterminated regexp meets end of file; expected a closing delimiter", 9..10]
]
end
@@ -189,14 +189,13 @@ module Prism
def test_unterminated_s_symbol
assert_errors expression("%s[abc"), "%s[abc", [
- ["expected a closing delimiter for the dynamic symbol", 0..3]
+ ["unterminated quoted string; expected a closing delimiter for the dynamic symbol", 0..3]
]
end
def test_unterminated_parenthesized_expression
assert_errors expression('(1 + 2'), '(1 + 2', [
- ["unexpected end of file, expecting end-of-input", 6..6],
- ["unexpected end of file, assuming it is closing the parent top level context", 6..6],
+ ["unexpected end-of-input, assuming it is closing the parent top level context", 6..6],
["expected a matching `)`", 6..6]
]
end
@@ -209,21 +208,21 @@ module Prism
def test_unterminated_argument_expression
assert_errors expression('a %'), 'a %', [
- ["invalid `%` token", 2..3],
- ["expected an expression after the operator", 2..3],
- ["unexpected end of file, assuming it is closing the parent top level context", 3..3]
+ ["unterminated quoted string meets end of file", 2..3],
+ ["unexpected end-of-input; expected an expression after the operator", 3..3],
+ ["unexpected end-of-input, assuming it is closing the parent top level context", 3..3]
]
end
def test_unterminated_interpolated_symbol
assert_error_messages ":\"#", [
- "expected a closing delimiter for the interpolated symbol"
+ "unterminated symbol; expected a closing delimiter for the interpolated symbol"
]
end
def test_cr_without_lf_in_percent_expression
assert_errors expression("%\r"), "%\r", [
- ["invalid `%` token", 0..2],
+ ["unterminated string meets end of file", 2..2],
]
end
@@ -365,7 +364,7 @@ module Prism
assert_error_messages "x.each { x end", [
"unexpected 'end', expecting end-of-input",
"unexpected 'end', ignoring it",
- "unexpected end of file, assuming it is closing the parent top level context",
+ "unexpected end-of-input, assuming it is closing the parent top level context",
"expected a block beginning with `{` to end with `}`"
]
end
@@ -378,10 +377,13 @@ module Prism
:a,
Location(),
Location(),
- ArgumentsNode(1, [
- KeywordHashNode(0, [AssocSplatNode(expression("kwargs"), Location())]),
- SplatNode(Location(), expression("args"))
- ]),
+ ArgumentsNode(
+ ArgumentsNodeFlags::CONTAINS_KEYWORDS | ArgumentsNodeFlags::CONTAINS_KEYWORD_SPLAT,
+ [
+ KeywordHashNode(0, [AssocSplatNode(expression("kwargs"), Location())]),
+ SplatNode(Location(), expression("args"))
+ ]
+ ),
Location(),
nil
)
@@ -425,7 +427,7 @@ module Prism
:a,
Location(),
Location(),
- ArgumentsNode(0, [
+ ArgumentsNode(ArgumentsNodeFlags::CONTAINS_KEYWORDS, [
KeywordHashNode(1, [
AssocNode(
SymbolNode(SymbolFlags::FORCED_US_ASCII_ENCODING, nil, Location(), Location(), "foo"),
@@ -690,13 +692,13 @@ module Prism
expected = StringNode(StringFlags::FORCED_UTF8_ENCODING, Location(), Location(), nil, "\u0001\u0002")
assert_errors expected, '?\u{0001 0002}', [
- ["invalid Unicode escape sequence; multiple codepoints are not allowed in a character literal", 9..12]
+ ["invalid Unicode escape sequence; Multiple codepoints at single character literal are disallowed", 9..12]
]
end
def test_invalid_hex_escape
assert_errors expression('"\\xx"'), '"\\xx"', [
- ["invalid hexadecimal escape sequence", 1..3],
+ ["invalid hex escape sequence", 1..3],
]
end
@@ -713,12 +715,13 @@ module Prism
assert_errors expected, '"\u{000z}"', [
["invalid Unicode escape sequence", 7..7],
+ ["unterminated Unicode escape", 7..7]
]
end
def test_unterminated_unicode_brackets_should_be_a_syntax_error
assert_errors expression('?\\u{3'), '?\\u{3', [
- ["invalid Unicode escape sequence; needs closing `}`", 1..5],
+ ["unterminated Unicode escape", 1..5],
]
end
@@ -861,7 +864,7 @@ module Prism
:foo,
Location(),
nil,
- ParametersNode([], [], nil, [], [], ForwardingParameterNode(), nil),
+ ParametersNode([], [], nil, [ForwardingParameterNode()], [], ForwardingParameterNode(), nil),
nil,
[],
Location(),
@@ -1094,7 +1097,7 @@ module Prism
ConstantReadNode(:A),
nil,
nil,
- StatementsNode([ReturnNode(Location(), nil)]),
+ StatementsNode([ReturnNode(0, Location(), nil)]),
Location(),
:A
)
@@ -1109,7 +1112,7 @@ module Prism
[],
Location(),
ConstantReadNode(:A),
- StatementsNode([ReturnNode(Location(), nil)]),
+ StatementsNode([ReturnNode(0, Location(), nil)]),
Location(),
:A
)
@@ -1238,7 +1241,7 @@ module Prism
expected = CallNode(0, receiver, Location(), :foo, Location(), nil, nil, nil, nil)
assert_errors expected, "<<~FOO.foo\n", [
- ["could not find a terminator for the heredoc", 11..11]
+ ["unterminated heredoc; can't find string \"FOO\" anywhere before EOF", 3..6]
]
end
@@ -1381,7 +1384,6 @@ module Prism
def test_invalid_number_underscores
error_messages = ["invalid underscore placement in number"]
-
assert_error_messages "1__1", error_messages
assert_error_messages "0b1__1", error_messages
assert_error_messages "0o1__1", error_messages
@@ -1389,6 +1391,7 @@ module Prism
assert_error_messages "0d1__1", error_messages
assert_error_messages "0x1__1", error_messages
+ error_messages = ["trailing '_' in number"]
assert_error_messages "1_1_", error_messages
assert_error_messages "0b1_1_", error_messages
assert_error_messages "0o1_1_", error_messages
@@ -1398,7 +1401,7 @@ module Prism
end
def test_alnum_delimiters
- error_messages = ["invalid `%` token"]
+ error_messages = ["unknown type of %string"]
assert_error_messages "%qXfooX", error_messages
assert_error_messages "%QXfooX", error_messages
@@ -1463,7 +1466,7 @@ module Prism
def test_forwarding_arg_after_keyword_rest
source = "def f(**,...);end"
assert_errors expression(source), source, [
- ["unexpected `...` in parameters", 9..12],
+ ["unexpected parameter order", 9..12]
]
end
@@ -1479,8 +1482,7 @@ module Prism
assert_errors expression(source), source, [
["expected a `do` keyword or a `{` to open the lambda block", 3..3],
- ["unexpected end of file, expecting end-of-input", 7..7],
- ["unexpected end of file, assuming it is closing the parent top level context", 7..7],
+ ["unexpected end-of-input, assuming it is closing the parent top level context", 7..7],
["expected a lambda block beginning with `do` to end with `end`", 7..7]
]
end
@@ -1538,7 +1540,7 @@ module Prism
assert_errors expression(source), source, [
["expected a predicate expression for the `while` statement", 22..22],
- ["unexpected end of file, assuming it is closing the parent top level context", 22..22],
+ ["unexpected end-of-input, assuming it is closing the parent top level context", 22..22],
["expected an `end` to close the `while` statement", 22..22]
]
end
@@ -1939,10 +1941,10 @@ module Prism
RUBY
assert_errors expression(source), source, [
- ["unexpected '..', expecting end-of-input", 3..5],
- ["unexpected '..', ignoring it", 3..5],
- ["unexpected '..', expecting end-of-input", 10..12],
- ["unexpected '..', ignoring it", 10..12]
+ ["unexpected .., expecting end-of-input", 3..5],
+ ["unexpected .., ignoring it", 3..5],
+ ["unexpected .., expecting end-of-input", 10..12],
+ ["unexpected .., ignoring it", 10..12]
]
end
@@ -2079,7 +2081,7 @@ module Prism
def test_forwarding_arg_and_block
source = 'def foo(...) = foo(...) { }'
assert_errors expression(source), source, [
- ['both a block argument and a forwarding argument; only one block is allowed', 24..27]
+ ['both block arg and actual block given; only one block is allowed', 24..27]
]
end
diff --git a/test/prism/format_errors_test.rb b/test/prism/format_errors_test.rb
index a1edbef2e8..63206d5765 100644
--- a/test/prism/format_errors_test.rb
+++ b/test/prism/format_errors_test.rb
@@ -6,19 +6,53 @@ return if Prism::BACKEND == :FFI
module Prism
class FormatErrorsTest < TestCase
- def test_format_errors
- assert_equal <<~ERROR, Debug.format_errors("<>", false)
+ def test_basic
+ expected = <<~ERROR
> 1 | <>
| ^ unexpected '<', ignoring it
| ^ unexpected '>', ignoring it
ERROR
- assert_equal <<~'ERROR', Debug.format_errors('"%W"\u"', false)
- > 1 | "%W"\u"
+ assert_equal expected, Debug.format_errors("<>", false)
+ end
+
+ def test_multiple
+ expected = <<~ERROR
+ > 1 | "%W"\\u"
| ^ unexpected backslash, ignoring it
| ^ unexpected local variable or method, expecting end-of-input
| ^ unterminated string meets end of file
ERROR
+
+ assert_equal expected, Debug.format_errors('"%W"\u"', false)
+ end
+
+ def test_truncate_start
+ expected = <<~ERROR
+ > 1 | ... <>
+ | ^ unexpected '<', ignoring it
+ | ^ unexpected '>', ignoring it
+ ERROR
+
+ assert_equal expected, Debug.format_errors("#{" " * 30}<>", false)
+ end
+
+ def test_truncate_end
+ expected = <<~ERROR
+ > 1 | <#{" " * 30} ...
+ | ^ unexpected '<', ignoring it
+ ERROR
+
+ assert_equal expected, Debug.format_errors("<#{" " * 30}a", false)
+ end
+
+ def test_truncate_both
+ expected = <<~ERROR
+ > 1 | ... <#{" " * 30} ...
+ | ^ unexpected '<', ignoring it
+ ERROR
+
+ assert_equal expected, Debug.format_errors("#{" " * 30}<#{" " * 30}a", false)
end
end
end
diff --git a/test/prism/index_write_test.rb b/test/prism/index_write_test.rb
index 1c6f7bce89..cf90eb082f 100644
--- a/test/prism/index_write_test.rb
+++ b/test/prism/index_write_test.rb
@@ -4,7 +4,7 @@ require_relative "test_helper"
module Prism
class IndexWriteTest < TestCase
- def test_keywords_3_3_0
+ def test_keywords_3_3
assert_parse_success(<<~RUBY, "3.3.0")
foo[bar: 1] = 1
foo[bar: 1] &&= 1
@@ -22,7 +22,7 @@ module Prism
RUBY
end
- def test_block_3_3_0
+ def test_block_3_3
assert_parse_success(<<~RUBY, "3.3.0")
foo[&bar] = 1
foo[&bar] &&= 1
@@ -40,41 +40,41 @@ module Prism
RUBY
end
- # def test_keywords_latest
- # assert_parse_failure(<<~RUBY)
- # foo[bar: 1] = 1
- # foo[bar: 1] &&= 1
- # foo[bar: 1] ||= 1
- # foo[bar: 1] += 1
- # RUBY
+ def test_keywords_latest
+ assert_parse_failure(<<~RUBY)
+ foo[bar: 1] = 1
+ foo[bar: 1] &&= 1
+ foo[bar: 1] ||= 1
+ foo[bar: 1] += 1
+ RUBY
- # assert_parse_failure(<<~RUBY)
- # def foo(**)
- # bar[**] = 1
- # bar[**] &&= 1
- # bar[**] ||= 1
- # bar[**] += 1
- # end
- # RUBY
- # end
+ assert_parse_failure(<<~RUBY)
+ def foo(**)
+ bar[**] = 1
+ bar[**] &&= 1
+ bar[**] ||= 1
+ bar[**] += 1
+ end
+ RUBY
+ end
- # def test_block_latest
- # assert_parse_failure(<<~RUBY)
- # foo[&bar] = 1
- # foo[&bar] &&= 1
- # foo[&bar] ||= 1
- # foo[&bar] += 1
- # RUBY
+ def test_block_latest
+ assert_parse_failure(<<~RUBY)
+ foo[&bar] = 1
+ foo[&bar] &&= 1
+ foo[&bar] ||= 1
+ foo[&bar] += 1
+ RUBY
- # assert_parse_failure(<<~RUBY)
- # def foo(&)
- # bar[&] = 1
- # bar[&] &&= 1
- # bar[&] ||= 1
- # bar[&] += 1
- # end
- # RUBY
- # end
+ assert_parse_failure(<<~RUBY)
+ def foo(&)
+ bar[&] = 1
+ bar[&] &&= 1
+ bar[&] ||= 1
+ bar[&] += 1
+ end
+ RUBY
+ end
private
diff --git a/test/prism/location_test.rb b/test/prism/location_test.rb
index 81417fbcb3..0724995671 100644
--- a/test/prism/location_test.rb
+++ b/test/prism/location_test.rb
@@ -298,7 +298,6 @@ module Prism
def test_ConstantReadNode
assert_location(ConstantReadNode, "Foo")
- assert_location(ConstantReadNode, "Foo::Bar", 5...8, &:child)
end
def test_ConstantTargetNode
@@ -478,7 +477,7 @@ module Prism
end
def test_IndexTargetNode
- assert_location(IndexTargetNode, "foo[bar, &baz], = qux", 0...14) do |node|
+ assert_location(IndexTargetNode, "foo[bar], = qux", 0...8) do |node|
node.lefts.first
end
end
diff --git a/test/prism/newline_test.rb b/test/prism/newline_test.rb
index e9975b346e..f7511f665c 100644
--- a/test/prism/newline_test.rb
+++ b/test/prism/newline_test.rb
@@ -7,7 +7,15 @@ return unless defined?(RubyVM::InstructionSequence)
module Prism
class NewlineTest < TestCase
base = File.expand_path("../", __FILE__)
- filepaths = Dir["*.rb", base: base] - %w[encoding_test.rb errors_test.rb parser_test.rb static_literals_test.rb unescape_test.rb]
+ filepaths = Dir["*.rb", base: base] - %w[
+ encoding_test.rb
+ errors_test.rb
+ format_errors_test.rb
+ parser_test.rb
+ regexp_test.rb
+ static_literals_test.rb
+ unescape_test.rb
+ ]
filepaths.each do |relative|
define_method("test_newline_flags_#{relative}") do
diff --git a/test/prism/redundant_return_test.rb b/test/prism/redundant_return_test.rb
new file mode 100644
index 0000000000..c668169245
--- /dev/null
+++ b/test/prism/redundant_return_test.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require_relative "test_helper"
+
+module Prism
+ class RedundantReturnTest < TestCase
+ def test_statements
+ assert_redundant_return("def foo; return; end")
+ refute_redundant_return("def foo; return; 1; end")
+ end
+
+ def test_begin_implicit
+ assert_redundant_return("def foo; return; rescue; end")
+ refute_redundant_return("def foo; return; 1; rescue; end")
+ refute_redundant_return("def foo; return; rescue; else; end")
+ end
+
+ def test_begin_explicit
+ assert_redundant_return("def foo; begin; return; rescue; end; end")
+ refute_redundant_return("def foo; begin; return; 1; rescue; end; end")
+ refute_redundant_return("def foo; begin; return; rescue; else; end; end")
+ end
+
+ def test_if
+ assert_redundant_return("def foo; return if bar; end")
+ end
+
+ def test_unless
+ assert_redundant_return("def foo; return unless bar; end")
+ end
+
+ def test_else
+ assert_redundant_return("def foo; if bar; baz; else; return; end; end")
+ end
+
+ def test_case_when
+ assert_redundant_return("def foo; case bar; when baz; return; end; end")
+ end
+
+ def test_case_else
+ assert_redundant_return("def foo; case bar; when baz; else; return; end; end")
+ end
+
+ def test_case_match_in
+ assert_redundant_return("def foo; case bar; in baz; return; end; end")
+ end
+
+ def test_case_match_else
+ assert_redundant_return("def foo; case bar; in baz; else; return; end; end")
+ end
+
+ private
+
+ def assert_redundant_return(source)
+ assert find_return(source).redundant?
+ end
+
+ def refute_redundant_return(source)
+ refute find_return(source).redundant?
+ end
+
+ def find_return(source)
+ queue = [Prism.parse(source).value]
+
+ while (current = queue.shift)
+ return current if current.is_a?(ReturnNode)
+ queue.concat(current.compact_child_nodes)
+ end
+
+ flunk "Could not find return node in #{node.inspect}"
+ end
+ end
+end
diff --git a/test/prism/ruby_api_test.rb b/test/prism/ruby_api_test.rb
index 6418887147..a1e2592d3d 100644
--- a/test/prism/ruby_api_test.rb
+++ b/test/prism/ruby_api_test.rb
@@ -209,6 +209,13 @@ module Prism
assert_equal "", location.slice
end
+ def test_location_slice_lines
+ result = Prism.parse("\nprivate def foo\nend\n")
+ method = result.value.statements.body.first.arguments.arguments.first
+
+ assert_equal "private def foo\nend\n", method.slice_lines
+ end
+
def test_heredoc?
refute parse_expression("\"foo\"").heredoc?
refute parse_expression("\"foo \#{1}\"").heredoc?
@@ -244,6 +251,53 @@ module Prism
assert_equal 16, base[parse_expression("0x1")]
end
+ def test_node_equality
+ assert_operator parse_expression("1"), :===, parse_expression("1")
+ assert_operator Prism.parse("1").value, :===, Prism.parse("1").value
+
+ complex_source = "class Something; @var = something.else { _1 }; end"
+ assert_operator parse_expression(complex_source), :===, parse_expression(complex_source)
+
+ refute_operator parse_expression("1"), :===, parse_expression("2")
+ refute_operator parse_expression("1"), :===, parse_expression("0x1")
+
+ complex_source_1 = "class Something; @var = something.else { _1 }; end"
+ complex_source_2 = "class Something; @var = something.else { _2 }; end"
+ refute_operator parse_expression(complex_source_1), :===, parse_expression(complex_source_2)
+ end
+
+ def test_node_tunnel
+ program = Prism.parse("foo(1) +\n bar(2, 3) +\n baz(3, 4, 5)").value
+
+ tunnel = program.tunnel(1, 4).last
+ assert_kind_of IntegerNode, tunnel
+ assert_equal 1, tunnel.value
+
+ tunnel = program.tunnel(2, 6).last
+ assert_kind_of IntegerNode, tunnel
+ assert_equal 2, tunnel.value
+
+ tunnel = program.tunnel(3, 9).last
+ assert_kind_of IntegerNode, tunnel
+ assert_equal 4, tunnel.value
+
+ tunnel = program.tunnel(3, 8)
+ assert_equal [ProgramNode, StatementsNode, CallNode, ArgumentsNode, CallNode, ArgumentsNode], tunnel.map(&:class)
+ end
+
+ def test_location_adjoin
+ program = Prism.parse("foo.bar = 1").value
+
+ location = program.statements.body.first.message_loc
+ adjoined = location.adjoin("=")
+
+ assert_kind_of Location, adjoined
+ refute_equal location, adjoined
+
+ assert_equal 4, adjoined.start_offset
+ assert_equal 9, adjoined.end_offset
+ end
+
private
def parse_expression(source)
diff --git a/test/prism/snapshots/arrays.txt b/test/prism/snapshots/arrays.txt
index e8e53aacb9..90a4d8f3bb 100644
--- a/test/prism/snapshots/arrays.txt
+++ b/test/prism/snapshots/arrays.txt
@@ -960,8 +960,8 @@
│ ├── arguments: ∅
│ ├── closing_loc: (84,4)-(84,5) = "]"
│ ├── block: ∅
- │ ├── operator: :+
- │ ├── operator_loc: (84,6)-(84,8) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (84,6)-(84,8) = "+="
│ └── value:
│ @ IntegerNode (location: (84,9)-(84,10))
│ ├── flags: decimal
@@ -1040,8 +1040,8 @@
│ ├── arguments: ∅
│ ├── closing_loc: (90,8)-(90,9) = "]"
│ ├── block: ∅
- │ ├── operator: :+
- │ ├── operator_loc: (90,10)-(90,12) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (90,10)-(90,12) = "+="
│ └── value:
│ @ IntegerNode (location: (90,13)-(90,14))
│ ├── flags: decimal
@@ -1143,8 +1143,8 @@
│ │ └── block: ∅
│ ├── closing_loc: (96,7)-(96,8) = "]"
│ ├── block: ∅
- │ ├── operator: :+
- │ ├── operator_loc: (96,9)-(96,11) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (96,9)-(96,11) = "+="
│ └── value:
│ @ IntegerNode (location: (96,12)-(96,13))
│ ├── flags: decimal
@@ -1262,8 +1262,8 @@
│ │ └── block: ∅
│ ├── closing_loc: (102,11)-(102,12) = "]"
│ ├── block: ∅
- │ ├── operator: :+
- │ ├── operator_loc: (102,13)-(102,15) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (102,13)-(102,15) = "+="
│ └── value:
│ @ IntegerNode (location: (102,16)-(102,17))
│ ├── flags: decimal
@@ -1633,8 +1633,8 @@
│ │ │ └── expression: ∅
│ │ ├── closing_loc: (116,13)-(116,14) = "]"
│ │ ├── block: ∅
- │ │ ├── operator: :+
- │ │ ├── operator_loc: (116,15)-(116,17) = "+="
+ │ │ ├── binary_operator: :+
+ │ │ ├── binary_operator_loc: (116,15)-(116,17) = "+="
│ │ └── value:
│ │ @ IntegerNode (location: (116,18)-(116,19))
│ │ ├── flags: decimal
diff --git a/test/prism/snapshots/blocks.txt b/test/prism/snapshots/blocks.txt
index 0b1ec52e38..1c996ebd09 100644
--- a/test/prism/snapshots/blocks.txt
+++ b/test/prism/snapshots/blocks.txt
@@ -158,13 +158,13 @@
│ │ └── body: (length: 1)
│ │ └── @ LocalVariableOperatorWriteNode (location: (7,24)-(7,33))
│ │ ├── name_loc: (7,24)-(7,28) = "memo"
- │ │ ├── operator_loc: (7,29)-(7,31) = "+="
+ │ │ ├── binary_operator_loc: (7,29)-(7,31) = "+="
│ │ ├── value:
│ │ │ @ LocalVariableReadNode (location: (7,32)-(7,33))
│ │ │ ├── name: :x
│ │ │ └── depth: 0
│ │ ├── name: :memo
- │ │ ├── operator: :+
+ │ │ ├── binary_operator: :+
│ │ └── depth: 0
│ ├── opening_loc: (7,12)-(7,13) = "{"
│ └── closing_loc: (7,34)-(7,35) = "}"
diff --git a/test/prism/snapshots/boolean_operators.txt b/test/prism/snapshots/boolean_operators.txt
index ace8047e18..3bf33430c9 100644
--- a/test/prism/snapshots/boolean_operators.txt
+++ b/test/prism/snapshots/boolean_operators.txt
@@ -21,7 +21,7 @@
│ └── depth: 0
├── @ LocalVariableOperatorWriteNode (location: (3,0)-(3,6))
│ ├── name_loc: (3,0)-(3,1) = "a"
- │ ├── operator_loc: (3,2)-(3,4) = "+="
+ │ ├── binary_operator_loc: (3,2)-(3,4) = "+="
│ ├── value:
│ │ @ CallNode (location: (3,5)-(3,6))
│ │ ├── flags: variable_call, ignore_visibility
@@ -34,7 +34,7 @@
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── name: :a
- │ ├── operator: :+
+ │ ├── binary_operator: :+
│ └── depth: 0
└── @ LocalVariableOrWriteNode (location: (5,0)-(5,7))
├── name_loc: (5,0)-(5,1) = "a"
diff --git a/test/prism/snapshots/constants.txt b/test/prism/snapshots/constants.txt
index 59e234148a..1251833663 100644
--- a/test/prism/snapshots/constants.txt
+++ b/test/prism/snapshots/constants.txt
@@ -7,24 +7,21 @@
│ ├── parent:
│ │ @ ConstantReadNode (location: (1,0)-(1,1))
│ │ └── name: :A
- │ ├── child:
- │ │ @ ConstantReadNode (location: (1,3)-(1,4))
- │ │ └── name: :B
- │ └── delimiter_loc: (1,1)-(1,3) = "::"
+ │ ├── name: :B
+ │ ├── delimiter_loc: (1,1)-(1,3) = "::"
+ │ └── name_loc: (1,3)-(1,4) = "B"
├── @ ConstantPathNode (location: (3,0)-(3,7))
│ ├── parent:
│ │ @ ConstantPathNode (location: (3,0)-(3,4))
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (3,0)-(3,1))
│ │ │ └── name: :A
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (3,3)-(3,4))
- │ │ │ └── name: :B
- │ │ └── delimiter_loc: (3,1)-(3,3) = "::"
- │ ├── child:
- │ │ @ ConstantReadNode (location: (3,6)-(3,7))
- │ │ └── name: :C
- │ └── delimiter_loc: (3,4)-(3,6) = "::"
+ │ │ ├── name: :B
+ │ │ ├── delimiter_loc: (3,1)-(3,3) = "::"
+ │ │ └── name_loc: (3,3)-(3,4) = "B"
+ │ ├── name: :C
+ │ ├── delimiter_loc: (3,4)-(3,6) = "::"
+ │ └── name_loc: (3,6)-(3,7) = "C"
├── @ ConstantPathNode (location: (5,0)-(5,4))
│ ├── parent:
│ │ @ CallNode (location: (5,0)-(5,1))
@@ -37,20 +34,18 @@
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (5,3)-(5,4))
- │ │ └── name: :B
- │ └── delimiter_loc: (5,1)-(5,3) = "::"
+ │ ├── name: :B
+ │ ├── delimiter_loc: (5,1)-(5,3) = "::"
+ │ └── name_loc: (5,3)-(5,4) = "B"
├── @ ConstantPathWriteNode (location: (7,0)-(7,8))
│ ├── target:
│ │ @ ConstantPathNode (location: (7,0)-(7,4))
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (7,0)-(7,1))
│ │ │ └── name: :A
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (7,3)-(7,4))
- │ │ │ └── name: :B
- │ │ └── delimiter_loc: (7,1)-(7,3) = "::"
+ │ │ ├── name: :B
+ │ │ ├── delimiter_loc: (7,1)-(7,3) = "::"
+ │ │ └── name_loc: (7,3)-(7,4) = "B"
│ ├── operator_loc: (7,5)-(7,6) = "="
│ └── value:
│ @ IntegerNode (location: (7,7)-(7,8))
@@ -117,7 +112,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (17,4)-(17,9))
- │ │ ├── flags: contains_keyword_splat
+ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (17,4)-(17,9))
│ │ ├── flags: ∅
@@ -199,7 +194,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (23,9)-(23,14))
- │ │ ├── flags: contains_keyword_splat
+ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (23,9)-(23,14))
│ │ ├── flags: ∅
@@ -249,10 +244,9 @@
│ ├── receiver:
│ │ @ ConstantPathNode (location: (27,0)-(27,3))
│ │ ├── parent: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (27,2)-(27,3))
- │ │ │ └── name: :A
- │ │ └── delimiter_loc: (27,0)-(27,2) = "::"
+ │ │ ├── name: :A
+ │ │ ├── delimiter_loc: (27,0)-(27,2) = "::"
+ │ │ └── name_loc: (27,2)-(27,3) = "A"
│ ├── call_operator_loc: (27,3)-(27,5) = "::"
│ ├── name: :foo
│ ├── message_loc: (27,5)-(27,8) = "foo"
@@ -264,10 +258,9 @@
│ ├── target:
│ │ @ ConstantPathNode (location: (29,0)-(29,3))
│ │ ├── parent: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (29,2)-(29,3))
- │ │ │ └── name: :A
- │ │ └── delimiter_loc: (29,0)-(29,2) = "::"
+ │ │ ├── name: :A
+ │ │ ├── delimiter_loc: (29,0)-(29,2) = "::"
+ │ │ └── name_loc: (29,2)-(29,3) = "A"
│ ├── operator_loc: (29,4)-(29,5) = "="
│ └── value:
│ @ IntegerNode (location: (29,6)-(29,7))
@@ -279,14 +272,12 @@
│ │ ├── parent:
│ │ │ @ ConstantPathNode (location: (31,0)-(31,3))
│ │ │ ├── parent: ∅
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (31,2)-(31,3))
- │ │ │ │ └── name: :A
- │ │ │ └── delimiter_loc: (31,0)-(31,2) = "::"
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (31,5)-(31,6))
- │ │ │ └── name: :B
- │ │ └── delimiter_loc: (31,3)-(31,5) = "::"
+ │ │ │ ├── name: :A
+ │ │ │ ├── delimiter_loc: (31,0)-(31,2) = "::"
+ │ │ │ └── name_loc: (31,2)-(31,3) = "A"
+ │ │ ├── name: :B
+ │ │ ├── delimiter_loc: (31,3)-(31,5) = "::"
+ │ │ └── name_loc: (31,5)-(31,6) = "B"
│ ├── operator_loc: (31,7)-(31,8) = "="
│ └── value:
│ @ IntegerNode (location: (31,9)-(31,10))
@@ -296,20 +287,17 @@
│ ├── parent:
│ │ @ ConstantPathNode (location: (33,0)-(33,3))
│ │ ├── parent: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (33,2)-(33,3))
- │ │ │ └── name: :A
- │ │ └── delimiter_loc: (33,0)-(33,2) = "::"
- │ ├── child:
- │ │ @ ConstantReadNode (location: (33,5)-(33,6))
- │ │ └── name: :B
- │ └── delimiter_loc: (33,3)-(33,5) = "::"
+ │ │ ├── name: :A
+ │ │ ├── delimiter_loc: (33,0)-(33,2) = "::"
+ │ │ └── name_loc: (33,2)-(33,3) = "A"
+ │ ├── name: :B
+ │ ├── delimiter_loc: (33,3)-(33,5) = "::"
+ │ └── name_loc: (33,5)-(33,6) = "B"
├── @ ConstantPathNode (location: (35,0)-(35,3))
│ ├── parent: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (35,2)-(35,3))
- │ │ └── name: :A
- │ └── delimiter_loc: (35,0)-(35,2) = "::"
+ │ ├── name: :A
+ │ ├── delimiter_loc: (35,0)-(35,2) = "::"
+ │ └── name_loc: (35,2)-(35,3) = "A"
├── @ CallNode (location: (37,0)-(37,8))
│ ├── flags: ∅
│ ├── receiver:
@@ -329,10 +317,9 @@
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (39,0)-(39,1))
│ │ │ └── name: :A
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (39,3)-(39,4))
- │ │ │ └── name: :B
- │ │ └── delimiter_loc: (39,1)-(39,3) = "::"
+ │ │ ├── name: :B
+ │ │ ├── delimiter_loc: (39,1)-(39,3) = "::"
+ │ │ └── name_loc: (39,3)-(39,4) = "B"
│ ├── call_operator_loc: (39,4)-(39,6) = "::"
│ ├── name: :true
│ ├── message_loc: (39,6)-(39,10) = "true"
@@ -488,10 +475,9 @@
│ ├── parent:
│ │ @ ConstantReadNode (location: (65,0)-(65,1))
│ │ └── name: :A
- │ ├── child:
- │ │ @ ConstantReadNode (location: (67,0)-(67,1))
- │ │ └── name: :C
- │ └── delimiter_loc: (65,1)-(65,3) = "::"
+ │ ├── name: :C
+ │ ├── delimiter_loc: (65,1)-(65,3) = "::"
+ │ └── name_loc: (67,0)-(67,1) = "C"
├── @ CallNode (location: (69,0)-(69,8))
│ ├── flags: ∅
│ ├── receiver:
@@ -532,10 +518,9 @@
│ ├── parent:
│ │ @ ConstantReadNode (location: (75,0)-(75,1))
│ │ └── name: :A
- │ ├── child:
- │ │ @ ConstantReadNode (location: (75,3)-(75,8))
- │ │ └── name: :BEGIN
- │ └── delimiter_loc: (75,1)-(75,3) = "::"
+ │ ├── name: :BEGIN
+ │ ├── delimiter_loc: (75,1)-(75,3) = "::"
+ │ └── name_loc: (75,3)-(75,8) = "BEGIN"
├── @ CallNode (location: (77,0)-(77,8))
│ ├── flags: ∅
│ ├── receiver:
@@ -636,10 +621,9 @@
│ ├── parent:
│ │ @ ConstantReadNode (location: (93,0)-(93,1))
│ │ └── name: :A
- │ ├── child:
- │ │ @ ConstantReadNode (location: (93,3)-(93,6))
- │ │ └── name: :END
- │ └── delimiter_loc: (93,1)-(93,3) = "::"
+ │ ├── name: :END
+ │ ├── delimiter_loc: (93,1)-(93,3) = "::"
+ │ └── name_loc: (93,3)-(93,6) = "END"
├── @ CallNode (location: (95,0)-(95,9))
│ ├── flags: ∅
│ ├── receiver:
@@ -1207,10 +1191,9 @@
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (180,0)-(180,1))
- │ │ └── name: :C
- │ └── delimiter_loc: (179,4)-(179,6) = "::"
+ │ ├── name: :C
+ │ ├── delimiter_loc: (179,4)-(179,6) = "::"
+ │ └── name_loc: (180,0)-(180,1) = "C"
└── @ RangeNode (location: (182,0)-(184,10))
├── flags: ∅
├── left:
diff --git a/test/prism/snapshots/defined.txt b/test/prism/snapshots/defined.txt
index 53a5081811..c60173ff37 100644
--- a/test/prism/snapshots/defined.txt
+++ b/test/prism/snapshots/defined.txt
@@ -28,13 +28,13 @@
│ ├── value:
│ │ @ LocalVariableOperatorWriteNode (location: (3,9)-(3,15))
│ │ ├── name_loc: (3,9)-(3,10) = "x"
- │ │ ├── operator_loc: (3,11)-(3,13) = "%="
+ │ │ ├── binary_operator_loc: (3,11)-(3,13) = "%="
│ │ ├── value:
│ │ │ @ IntegerNode (location: (3,14)-(3,15))
│ │ │ ├── flags: decimal
│ │ │ └── value: 2
│ │ ├── name: :x
- │ │ ├── operator: :%
+ │ │ ├── binary_operator: :%
│ │ └── depth: 0
│ ├── rparen_loc: (3,15)-(3,16) = ")"
│ └── keyword_loc: (3,0)-(3,8) = "defined?"
diff --git a/test/prism/snapshots/heredocs_nested.txt b/test/prism/snapshots/heredocs_nested.txt
index f830b028c7..da13e48c51 100644
--- a/test/prism/snapshots/heredocs_nested.txt
+++ b/test/prism/snapshots/heredocs_nested.txt
@@ -4,7 +4,7 @@
@ StatementsNode (location: (1,0)-(12,4))
└── body: (length: 2)
├── @ InterpolatedStringNode (location: (1,0)-(1,7))
- │ ├── flags: ∅
+ │ ├── flags: mutable
│ ├── opening_loc: (1,0)-(1,7) = "<<~RUBY"
│ ├── parts: (length: 4)
│ │ ├── @ StringNode (location: (2,0)-(3,0))
@@ -19,7 +19,7 @@
│ │ │ │ @ StatementsNode (location: (4,0)-(4,6))
│ │ │ │ └── body: (length: 1)
│ │ │ │ └── @ StringNode (location: (4,0)-(4,6))
- │ │ │ │ ├── flags: ∅
+ │ │ │ │ ├── flags: frozen
│ │ │ │ ├── opening_loc: (4,0)-(4,6) = "<<RUBY"
│ │ │ │ ├── content_loc: (5,0)-(6,0) = " hello\n"
│ │ │ │ ├── closing_loc: (6,0)-(7,0) = "RUBY\n"
diff --git a/test/prism/snapshots/if.txt b/test/prism/snapshots/if.txt
index eb33d1699d..4114d22722 100644
--- a/test/prism/snapshots/if.txt
+++ b/test/prism/snapshots/if.txt
@@ -162,6 +162,7 @@
│ │ @ StatementsNode (location: (14,0)-(14,6))
│ │ └── body: (length: 1)
│ │ └── @ ReturnNode (location: (14,0)-(14,6))
+ │ │ ├── flags: ∅
│ │ ├── keyword_loc: (14,0)-(14,6) = "return"
│ │ └── arguments: ∅
│ ├── consequent: ∅
@@ -306,7 +307,7 @@
│ │ ├── opening_loc: ∅
│ │ ├── arguments:
│ │ │ @ ArgumentsNode (location: (25,4)-(25,6))
- │ │ │ ├── flags: ∅
+ │ │ │ ├── flags: contains_keywords
│ │ │ └── arguments: (length: 1)
│ │ │ └── @ KeywordHashNode (location: (25,4)-(25,6))
│ │ │ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/method_calls.txt b/test/prism/snapshots/method_calls.txt
index de9ba71ae0..6082b567f7 100644
--- a/test/prism/snapshots/method_calls.txt
+++ b/test/prism/snapshots/method_calls.txt
@@ -308,7 +308,7 @@
│ ├── opening_loc: (27,1)-(27,2) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (27,2)-(27,10))
- │ │ ├── flags: contains_keyword_splat
+ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (27,2)-(27,10))
│ │ ├── flags: ∅
@@ -779,7 +779,7 @@
│ ├── opening_loc: (60,3)-(60,4) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (60,4)-(60,32))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 2)
│ │ ├── @ SymbolNode (location: (60,4)-(60,6))
│ │ │ ├── flags: forced_us_ascii_encoding
@@ -912,7 +912,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (64,4)-(64,15))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 2)
│ │ ├── @ SymbolNode (location: (64,4)-(64,6))
│ │ │ ├── flags: forced_us_ascii_encoding
@@ -988,7 +988,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (66,3)-(66,17))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (66,3)-(66,17))
│ │ ├── flags: symbol_keys
@@ -1020,7 +1020,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (68,3)-(68,40))
- │ │ ├── flags: contains_keyword_splat
+ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (68,3)-(68,40))
│ │ ├── flags: ∅
@@ -1075,7 +1075,7 @@
│ ├── opening_loc: (70,2)-(70,3) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (70,3)-(70,40))
- │ │ ├── flags: contains_keyword_splat
+ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (70,3)-(70,40))
│ │ ├── flags: ∅
@@ -1178,7 +1178,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (74,3)-(74,20))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (74,3)-(74,20))
│ │ ├── flags: symbol_keys
@@ -1235,7 +1235,7 @@
│ ├── opening_loc: (80,3)-(80,4) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (81,0)-(82,5))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 2)
│ │ ├── @ SymbolNode (location: (81,0)-(81,2))
│ │ │ ├── flags: forced_us_ascii_encoding
@@ -1292,7 +1292,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (87,4)-(87,21))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (87,4)-(87,21))
│ │ ├── flags: symbol_keys
@@ -1339,7 +1339,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (89,10)-(89,21))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 2)
│ │ ├── @ IntegerNode (location: (89,10)-(89,11))
│ │ │ ├── flags: decimal
@@ -1443,10 +1443,9 @@
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (97,0)-(97,1))
│ │ │ └── name: :A
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (97,3)-(97,4))
- │ │ │ └── name: :B
- │ │ └── delimiter_loc: (97,1)-(97,3) = "::"
+ │ │ ├── name: :B
+ │ │ ├── delimiter_loc: (97,1)-(97,3) = "::"
+ │ │ └── name_loc: (97,3)-(97,4) = "B"
│ ├── call_operator_loc: (97,4)-(97,6) = "::"
│ ├── name: :C
│ ├── message_loc: (97,6)-(97,7) = "C"
@@ -1470,10 +1469,9 @@
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (99,0)-(99,1))
│ │ │ └── name: :A
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (99,3)-(99,4))
- │ │ │ └── name: :B
- │ │ └── delimiter_loc: (99,1)-(99,3) = "::"
+ │ │ ├── name: :B
+ │ │ ├── delimiter_loc: (99,1)-(99,3) = "::"
+ │ │ └── name_loc: (99,3)-(99,4) = "B"
│ ├── call_operator_loc: (99,4)-(99,6) = "::"
│ ├── name: :C
│ ├── message_loc: (99,6)-(99,7) = "C"
@@ -1497,10 +1495,9 @@
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (101,0)-(101,1))
│ │ │ └── name: :A
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (101,3)-(101,4))
- │ │ │ └── name: :B
- │ │ └── delimiter_loc: (101,1)-(101,3) = "::"
+ │ │ ├── name: :B
+ │ │ ├── delimiter_loc: (101,1)-(101,3) = "::"
+ │ │ └── name_loc: (101,3)-(101,4) = "B"
│ ├── call_operator_loc: (101,4)-(101,6) = "::"
│ ├── name: :C
│ ├── message_loc: (101,6)-(101,7) = "C"
@@ -1532,7 +1529,7 @@
│ ├── opening_loc: (103,3)-(103,4) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (103,4)-(103,11))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (103,4)-(103,11))
│ │ ├── flags: symbol_keys
@@ -1561,7 +1558,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (105,4)-(105,28))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (105,4)-(105,28))
│ │ ├── flags: symbol_keys
@@ -1617,7 +1614,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (107,4)-(107,24))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (107,4)-(107,24))
│ │ ├── flags: symbol_keys
@@ -2417,7 +2414,7 @@
├── opening_loc: ∅
├── arguments:
│ @ ArgumentsNode (location: (156,5)-(156,19))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (156,5)-(156,19))
│ ├── flags: ∅
diff --git a/test/prism/snapshots/methods.txt b/test/prism/snapshots/methods.txt
index 22580494a4..b38640399b 100644
--- a/test/prism/snapshots/methods.txt
+++ b/test/prism/snapshots/methods.txt
@@ -814,6 +814,7 @@
│ │ │ │ @ StatementsNode (location: (99,0)-(99,10))
│ │ │ │ └── body: (length: 1)
│ │ │ │ └── @ ReturnNode (location: (99,0)-(99,10))
+ │ │ │ │ ├── flags: ∅
│ │ │ │ ├── keyword_loc: (99,0)-(99,6) = "return"
│ │ │ │ └── arguments:
│ │ │ │ @ ArgumentsNode (location: (99,7)-(99,10))
@@ -1295,7 +1296,7 @@
│ │ ├── opening_loc: ∅
│ │ ├── arguments:
│ │ │ @ ArgumentsNode (location: (139,11)-(139,30))
- │ │ │ ├── flags: contains_keyword_splat
+ │ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ │ └── arguments: (length: 1)
│ │ │ └── @ KeywordHashNode (location: (139,11)-(139,30))
│ │ │ ├── flags: ∅
diff --git a/test/prism/snapshots/modules.txt b/test/prism/snapshots/modules.txt
index 1a0eb6328a..de1ea8feeb 100644
--- a/test/prism/snapshots/modules.txt
+++ b/test/prism/snapshots/modules.txt
@@ -72,10 +72,9 @@
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (5,10)-(5,11))
- │ │ │ └── name: :M
- │ │ └── delimiter_loc: (5,8)-(5,10) = "::"
+ │ │ ├── name: :M
+ │ │ ├── delimiter_loc: (5,8)-(5,10) = "::"
+ │ │ └── name_loc: (5,10)-(5,11) = "M"
│ ├── body: ∅
│ ├── end_keyword_loc: (6,0)-(6,3) = "end"
│ └── name: :M
@@ -119,10 +118,9 @@
│ ├── constant_path:
│ │ @ ConstantPathNode (location: (11,7)-(11,10))
│ │ ├── parent: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (11,9)-(11,10))
- │ │ │ └── name: :A
- │ │ └── delimiter_loc: (11,7)-(11,9) = "::"
+ │ │ ├── name: :A
+ │ │ ├── delimiter_loc: (11,7)-(11,9) = "::"
+ │ │ └── name_loc: (11,9)-(11,10) = "A"
│ ├── body: ∅
│ ├── end_keyword_loc: (12,0)-(12,3) = "end"
│ └── name: :A
@@ -144,10 +142,9 @@
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: (14,9)-(14,10) = "]"
│ │ │ └── block: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (14,12)-(14,13))
- │ │ │ └── name: :B
- │ │ └── delimiter_loc: (14,10)-(14,12) = "::"
+ │ │ ├── name: :B
+ │ │ ├── delimiter_loc: (14,10)-(14,12) = "::"
+ │ │ └── name_loc: (14,12)-(14,13) = "B"
│ ├── body: ∅
│ ├── end_keyword_loc: (15,0)-(15,3) = "end"
│ └── name: :B
@@ -175,10 +172,9 @@
│ │ │ └── value: 1
│ │ ├── closing_loc: (17,10)-(17,11) = "]"
│ │ └── block: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (17,13)-(17,14))
- │ │ └── name: :B
- │ └── delimiter_loc: (17,11)-(17,13) = "::"
+ │ ├── name: :B
+ │ ├── delimiter_loc: (17,11)-(17,13) = "::"
+ │ └── name_loc: (17,13)-(17,14) = "B"
├── body: ∅
├── end_keyword_loc: (18,0)-(18,3) = "end"
└── name: :B
diff --git a/test/prism/snapshots/patterns.txt b/test/prism/snapshots/patterns.txt
index 5662129dae..16298e7984 100644
--- a/test/prism/snapshots/patterns.txt
+++ b/test/prism/snapshots/patterns.txt
@@ -1454,14 +1454,12 @@
│ │ │ ├── parent:
│ │ │ │ @ ConstantReadNode (location: (64,7)-(64,10))
│ │ │ │ └── name: :Foo
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (64,12)-(64,15))
- │ │ │ │ └── name: :Bar
- │ │ │ └── delimiter_loc: (64,10)-(64,12) = "::"
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (64,17)-(64,20))
- │ │ │ └── name: :Baz
- │ │ └── delimiter_loc: (64,15)-(64,17) = "::"
+ │ │ │ ├── name: :Bar
+ │ │ │ ├── delimiter_loc: (64,10)-(64,12) = "::"
+ │ │ │ └── name_loc: (64,12)-(64,15) = "Bar"
+ │ │ ├── name: :Baz
+ │ │ ├── delimiter_loc: (64,15)-(64,17) = "::"
+ │ │ └── name_loc: (64,17)-(64,20) = "Baz"
│ └── operator_loc: (64,4)-(64,6) = "=>"
├── @ MatchRequiredNode (location: (65,0)-(65,12))
│ ├── value:
@@ -1478,10 +1476,9 @@
│ ├── pattern:
│ │ @ ConstantPathNode (location: (65,7)-(65,12))
│ │ ├── parent: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (65,9)-(65,12))
- │ │ │ └── name: :Foo
- │ │ └── delimiter_loc: (65,7)-(65,9) = "::"
+ │ │ ├── name: :Foo
+ │ │ ├── delimiter_loc: (65,7)-(65,9) = "::"
+ │ │ └── name_loc: (65,9)-(65,12) = "Foo"
│ └── operator_loc: (65,4)-(65,6) = "=>"
├── @ MatchRequiredNode (location: (66,0)-(66,22))
│ ├── value:
@@ -1502,18 +1499,15 @@
│ │ │ ├── parent:
│ │ │ │ @ ConstantPathNode (location: (66,7)-(66,12))
│ │ │ │ ├── parent: ∅
- │ │ │ │ ├── child:
- │ │ │ │ │ @ ConstantReadNode (location: (66,9)-(66,12))
- │ │ │ │ │ └── name: :Foo
- │ │ │ │ └── delimiter_loc: (66,7)-(66,9) = "::"
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (66,14)-(66,17))
- │ │ │ │ └── name: :Bar
- │ │ │ └── delimiter_loc: (66,12)-(66,14) = "::"
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (66,19)-(66,22))
- │ │ │ └── name: :Baz
- │ │ └── delimiter_loc: (66,17)-(66,19) = "::"
+ │ │ │ │ ├── name: :Foo
+ │ │ │ │ ├── delimiter_loc: (66,7)-(66,9) = "::"
+ │ │ │ │ └── name_loc: (66,9)-(66,12) = "Foo"
+ │ │ │ ├── name: :Bar
+ │ │ │ ├── delimiter_loc: (66,12)-(66,14) = "::"
+ │ │ │ └── name_loc: (66,14)-(66,17) = "Bar"
+ │ │ ├── name: :Baz
+ │ │ ├── delimiter_loc: (66,17)-(66,19) = "::"
+ │ │ └── name_loc: (66,19)-(66,22) = "Baz"
│ └── operator_loc: (66,4)-(66,6) = "=>"
├── @ MatchRequiredNode (location: (68,0)-(68,12))
│ ├── value:
diff --git a/test/prism/snapshots/rescue.txt b/test/prism/snapshots/rescue.txt
index 57cafde5a6..390b08ae0e 100644
--- a/test/prism/snapshots/rescue.txt
+++ b/test/prism/snapshots/rescue.txt
@@ -88,6 +88,7 @@
├── @ RescueModifierNode (location: (10,0)-(10,17))
│ ├── expression:
│ │ @ ReturnNode (location: (10,0)-(10,6))
+ │ │ ├── flags: ∅
│ │ ├── keyword_loc: (10,0)-(10,6) = "return"
│ │ └── arguments: ∅
│ ├── keyword_loc: (10,7)-(10,13) = "rescue"
@@ -379,7 +380,7 @@
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments:
│ │ │ │ @ ArgumentsNode (location: (29,4)-(29,6))
- │ │ │ │ ├── flags: ∅
+ │ │ │ │ ├── flags: contains_keywords
│ │ │ │ └── arguments: (length: 1)
│ │ │ │ └── @ KeywordHashNode (location: (29,4)-(29,6))
│ │ │ │ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/return.txt b/test/prism/snapshots/return.txt
index 9a33076193..0dd26281c1 100644
--- a/test/prism/snapshots/return.txt
+++ b/test/prism/snapshots/return.txt
@@ -4,9 +4,11 @@
@ StatementsNode (location: (1,0)-(23,9))
└── body: (length: 10)
├── @ ReturnNode (location: (1,0)-(1,6))
+ │ ├── flags: ∅
│ ├── keyword_loc: (1,0)-(1,6) = "return"
│ └── arguments: ∅
├── @ ReturnNode (location: (3,0)-(3,20))
+ │ ├── flags: ∅
│ ├── keyword_loc: (3,0)-(3,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (3,7)-(3,20))
@@ -40,6 +42,7 @@
│ ├── opening_loc: (3,17)-(3,18) = "("
│ └── closing_loc: (3,19)-(3,20) = ")"
├── @ ReturnNode (location: (5,0)-(5,9))
+ │ ├── flags: ∅
│ ├── keyword_loc: (5,0)-(5,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (5,7)-(5,9))
@@ -52,6 +55,7 @@
│ ├── flags: decimal
│ └── value: 1
├── @ ReturnNode (location: (7,0)-(7,8))
+ │ ├── flags: ∅
│ ├── keyword_loc: (7,0)-(7,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (7,7)-(7,8))
@@ -61,6 +65,7 @@
│ ├── flags: decimal
│ └── value: 1
├── @ ReturnNode (location: (9,0)-(10,1))
+ │ ├── flags: ∅
│ ├── keyword_loc: (9,0)-(9,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (9,7)-(10,1))
@@ -76,6 +81,7 @@
│ ├── flags: decimal
│ └── value: 3
├── @ ReturnNode (location: (12,0)-(12,14))
+ │ ├── flags: ∅
│ ├── keyword_loc: (12,0)-(12,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (12,7)-(12,14))
@@ -91,6 +97,7 @@
│ ├── flags: decimal
│ └── value: 3
├── @ ReturnNode (location: (14,0)-(14,16))
+ │ ├── flags: ∅
│ ├── keyword_loc: (14,0)-(14,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (14,7)-(14,16))
@@ -111,6 +118,7 @@
│ ├── opening_loc: (14,7)-(14,8) = "["
│ └── closing_loc: (14,15)-(14,16) = "]"
├── @ ReturnNode (location: (16,0)-(19,1))
+ │ ├── flags: ∅
│ ├── keyword_loc: (16,0)-(16,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (16,6)-(19,1))
@@ -129,6 +137,7 @@
│ ├── opening_loc: (16,6)-(16,7) = "("
│ └── closing_loc: (19,0)-(19,1) = ")"
├── @ ReturnNode (location: (21,0)-(21,8))
+ │ ├── flags: ∅
│ ├── keyword_loc: (21,0)-(21,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (21,6)-(21,8))
@@ -139,6 +148,7 @@
│ ├── opening_loc: (21,6)-(21,7) = "("
│ └── closing_loc: (21,7)-(21,8) = ")"
└── @ ReturnNode (location: (23,0)-(23,9))
+ ├── flags: ∅
├── keyword_loc: (23,0)-(23,6) = "return"
└── arguments:
@ ArgumentsNode (location: (23,6)-(23,9))
diff --git a/test/prism/snapshots/seattlerb/assoc_label.txt b/test/prism/snapshots/seattlerb/assoc_label.txt
index 923f5450f4..70490c0da4 100644
--- a/test/prism/snapshots/seattlerb/assoc_label.txt
+++ b/test/prism/snapshots/seattlerb/assoc_label.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,1)-(1,2) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(1,5))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (1,2)-(1,5))
│ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/seattlerb/block_return.txt b/test/prism/snapshots/seattlerb/block_return.txt
index e91f5f2592..c863b28a22 100644
--- a/test/prism/snapshots/seattlerb/block_return.txt
+++ b/test/prism/snapshots/seattlerb/block_return.txt
@@ -4,6 +4,7 @@
@ StatementsNode (location: (1,0)-(1,27))
└── body: (length: 1)
└── @ ReturnNode (location: (1,0)-(1,27))
+ ├── flags: ∅
├── keyword_loc: (1,0)-(1,6) = "return"
└── arguments:
@ ArgumentsNode (location: (1,7)-(1,27))
diff --git a/test/prism/snapshots/seattlerb/bug_249.txt b/test/prism/snapshots/seattlerb/bug_249.txt
index 569bea14c5..ad61501a07 100644
--- a/test/prism/snapshots/seattlerb/bug_249.txt
+++ b/test/prism/snapshots/seattlerb/bug_249.txt
@@ -12,7 +12,7 @@
├── opening_loc: ∅
├── arguments:
│ @ ArgumentsNode (location: (1,6)-(4,28))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 2)
│ ├── @ CallNode (location: (1,6)-(4,9))
│ │ ├── flags: ∅
diff --git a/test/prism/snapshots/seattlerb/bug_hash_args.txt b/test/prism/snapshots/seattlerb/bug_hash_args.txt
index 6f17e88714..e138db4d49 100644
--- a/test/prism/snapshots/seattlerb/bug_hash_args.txt
+++ b/test/prism/snapshots/seattlerb/bug_hash_args.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,3)-(1,4) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,4)-(1,18))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 2)
│ ├── @ SymbolNode (location: (1,4)-(1,8))
│ │ ├── flags: forced_us_ascii_encoding
diff --git a/test/prism/snapshots/seattlerb/bug_hash_args_trailing_comma.txt b/test/prism/snapshots/seattlerb/bug_hash_args_trailing_comma.txt
index e7256b337b..fe2d7f73c9 100644
--- a/test/prism/snapshots/seattlerb/bug_hash_args_trailing_comma.txt
+++ b/test/prism/snapshots/seattlerb/bug_hash_args_trailing_comma.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,3)-(1,4) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,4)-(1,18))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 2)
│ ├── @ SymbolNode (location: (1,4)-(1,8))
│ │ ├── flags: forced_us_ascii_encoding
diff --git a/test/prism/snapshots/seattlerb/call_arg_assoc.txt b/test/prism/snapshots/seattlerb/call_arg_assoc.txt
index 27c19fd339..f489bc7f19 100644
--- a/test/prism/snapshots/seattlerb/call_arg_assoc.txt
+++ b/test/prism/snapshots/seattlerb/call_arg_assoc.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,1)-(1,2) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(1,9))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 2)
│ ├── @ IntegerNode (location: (1,2)-(1,3))
│ │ ├── flags: decimal
diff --git a/test/prism/snapshots/seattlerb/call_arg_assoc_kwsplat.txt b/test/prism/snapshots/seattlerb/call_arg_assoc_kwsplat.txt
index 0193eb1dfc..5b191396de 100644
--- a/test/prism/snapshots/seattlerb/call_arg_assoc_kwsplat.txt
+++ b/test/prism/snapshots/seattlerb/call_arg_assoc_kwsplat.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,1)-(1,2) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(1,15))
- │ ├── flags: contains_keyword_splat
+ │ ├── flags: contains_keywords, contains_keyword_splat
│ └── arguments: (length: 2)
│ ├── @ IntegerNode (location: (1,2)-(1,3))
│ │ ├── flags: decimal
diff --git a/test/prism/snapshots/seattlerb/call_arg_kwsplat.txt b/test/prism/snapshots/seattlerb/call_arg_kwsplat.txt
index 91c7725525..f95b80cf7d 100644
--- a/test/prism/snapshots/seattlerb/call_arg_kwsplat.txt
+++ b/test/prism/snapshots/seattlerb/call_arg_kwsplat.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,1)-(1,2) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(1,8))
- │ ├── flags: contains_keyword_splat
+ │ ├── flags: contains_keywords, contains_keyword_splat
│ └── arguments: (length: 2)
│ ├── @ CallNode (location: (1,2)-(1,3))
│ │ ├── flags: variable_call, ignore_visibility
diff --git a/test/prism/snapshots/seattlerb/call_args_assoc_quoted.txt b/test/prism/snapshots/seattlerb/call_args_assoc_quoted.txt
index 2d6f81c818..8946206a3f 100644
--- a/test/prism/snapshots/seattlerb/call_args_assoc_quoted.txt
+++ b/test/prism/snapshots/seattlerb/call_args_assoc_quoted.txt
@@ -12,7 +12,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (1,2)-(1,11))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (1,2)-(1,11))
│ │ ├── flags: ∅
@@ -55,7 +55,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (3,2)-(3,8))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (3,2)-(3,8))
│ │ ├── flags: symbol_keys
@@ -84,7 +84,7 @@
├── opening_loc: ∅
├── arguments:
│ @ ArgumentsNode (location: (5,2)-(5,8))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (5,2)-(5,8))
│ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/seattlerb/call_args_assoc_trailing_comma.txt b/test/prism/snapshots/seattlerb/call_args_assoc_trailing_comma.txt
index 312a1981a0..0ba5891cf6 100644
--- a/test/prism/snapshots/seattlerb/call_args_assoc_trailing_comma.txt
+++ b/test/prism/snapshots/seattlerb/call_args_assoc_trailing_comma.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,1)-(1,2) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(1,9))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 2)
│ ├── @ IntegerNode (location: (1,2)-(1,3))
│ │ ├── flags: decimal
diff --git a/test/prism/snapshots/seattlerb/call_assoc.txt b/test/prism/snapshots/seattlerb/call_assoc.txt
index 438c256553..60784e6095 100644
--- a/test/prism/snapshots/seattlerb/call_assoc.txt
+++ b/test/prism/snapshots/seattlerb/call_assoc.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,1)-(1,2) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(1,6))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (1,2)-(1,6))
│ ├── flags: ∅
diff --git a/test/prism/snapshots/seattlerb/call_assoc_new.txt b/test/prism/snapshots/seattlerb/call_assoc_new.txt
index b4d7e0bf83..dc25fb2493 100644
--- a/test/prism/snapshots/seattlerb/call_assoc_new.txt
+++ b/test/prism/snapshots/seattlerb/call_assoc_new.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,1)-(1,2) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(1,5))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (1,2)-(1,5))
│ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt b/test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt
index 9587e2e074..b3d652e879 100644
--- a/test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt
+++ b/test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,1)-(1,2) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(5,3))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (1,2)-(5,3))
│ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/seattlerb/call_assoc_trailing_comma.txt b/test/prism/snapshots/seattlerb/call_assoc_trailing_comma.txt
index 8d0b285172..b2012f0f75 100644
--- a/test/prism/snapshots/seattlerb/call_assoc_trailing_comma.txt
+++ b/test/prism/snapshots/seattlerb/call_assoc_trailing_comma.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,1)-(1,2) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(1,6))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (1,2)-(1,6))
│ ├── flags: ∅
diff --git a/test/prism/snapshots/seattlerb/call_kwsplat.txt b/test/prism/snapshots/seattlerb/call_kwsplat.txt
index 4199e97a44..e0620dc5f0 100644
--- a/test/prism/snapshots/seattlerb/call_kwsplat.txt
+++ b/test/prism/snapshots/seattlerb/call_kwsplat.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,1)-(1,2) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(1,5))
- │ ├── flags: contains_keyword_splat
+ │ ├── flags: contains_keywords, contains_keyword_splat
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (1,2)-(1,5))
│ ├── flags: ∅
diff --git a/test/prism/snapshots/seattlerb/case_in_86.txt b/test/prism/snapshots/seattlerb/case_in_86.txt
index 5889137844..082aa74eca 100644
--- a/test/prism/snapshots/seattlerb/case_in_86.txt
+++ b/test/prism/snapshots/seattlerb/case_in_86.txt
@@ -30,10 +30,9 @@
│ │ ├── requireds: (length: 1)
│ │ │ └── @ ConstantPathNode (location: (2,3)-(2,13))
│ │ │ ├── parent: ∅
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (2,5)-(2,13))
- │ │ │ │ └── name: :NilClass
- │ │ │ └── delimiter_loc: (2,3)-(2,5) = "::"
+ │ │ │ ├── name: :NilClass
+ │ │ │ ├── delimiter_loc: (2,3)-(2,5) = "::"
+ │ │ │ └── name_loc: (2,5)-(2,13) = "NilClass"
│ │ ├── rest:
│ │ │ @ SplatNode (location: (2,15)-(2,16))
│ │ │ ├── operator_loc: (2,15)-(2,16) = "*"
diff --git a/test/prism/snapshots/seattlerb/case_in_86_2.txt b/test/prism/snapshots/seattlerb/case_in_86_2.txt
index 18ce70ae93..346264f907 100644
--- a/test/prism/snapshots/seattlerb/case_in_86_2.txt
+++ b/test/prism/snapshots/seattlerb/case_in_86_2.txt
@@ -35,10 +35,9 @@
│ │ ├── posts: (length: 1)
│ │ │ └── @ ConstantPathNode (location: (2,6)-(2,16))
│ │ │ ├── parent: ∅
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (2,8)-(2,16))
- │ │ │ │ └── name: :NilClass
- │ │ │ └── delimiter_loc: (2,6)-(2,8) = "::"
+ │ │ │ ├── name: :NilClass
+ │ │ │ ├── delimiter_loc: (2,6)-(2,8) = "::"
+ │ │ │ └── name_loc: (2,8)-(2,16) = "NilClass"
│ │ ├── opening_loc: ∅
│ │ └── closing_loc: ∅
│ ├── statements:
diff --git a/test/prism/snapshots/seattlerb/case_in_array_pat_const2.txt b/test/prism/snapshots/seattlerb/case_in_array_pat_const2.txt
index c783af9ce5..d6fb80ef90 100644
--- a/test/prism/snapshots/seattlerb/case_in_array_pat_const2.txt
+++ b/test/prism/snapshots/seattlerb/case_in_array_pat_const2.txt
@@ -20,10 +20,9 @@
│ │ │ ├── parent:
│ │ │ │ @ ConstantReadNode (location: (2,3)-(2,4))
│ │ │ │ └── name: :B
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (2,6)-(2,7))
- │ │ │ │ └── name: :C
- │ │ │ └── delimiter_loc: (2,4)-(2,6) = "::"
+ │ │ │ ├── name: :C
+ │ │ │ ├── delimiter_loc: (2,4)-(2,6) = "::"
+ │ │ │ └── name_loc: (2,6)-(2,7) = "C"
│ │ ├── requireds: (length: 1)
│ │ │ └── @ LocalVariableTargetNode (location: (2,8)-(2,9))
│ │ │ ├── name: :d
diff --git a/test/prism/snapshots/seattlerb/case_in_multiple.txt b/test/prism/snapshots/seattlerb/case_in_multiple.txt
index d8597c4bfa..eba0084f96 100644
--- a/test/prism/snapshots/seattlerb/case_in_multiple.txt
+++ b/test/prism/snapshots/seattlerb/case_in_multiple.txt
@@ -18,10 +18,9 @@
│ │ │ ├── parent:
│ │ │ │ @ ConstantReadNode (location: (2,3)-(2,4))
│ │ │ │ └── name: :A
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (2,6)-(2,7))
- │ │ │ │ └── name: :B
- │ │ │ └── delimiter_loc: (2,4)-(2,6) = "::"
+ │ │ │ ├── name: :B
+ │ │ │ ├── delimiter_loc: (2,4)-(2,6) = "::"
+ │ │ │ └── name_loc: (2,6)-(2,7) = "B"
│ │ ├── statements:
│ │ │ @ StatementsNode (location: (3,2)-(3,4))
│ │ │ └── body: (length: 1)
@@ -39,10 +38,9 @@
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (4,3)-(4,4))
│ │ │ └── name: :D
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (4,6)-(4,7))
- │ │ │ └── name: :E
- │ │ └── delimiter_loc: (4,4)-(4,6) = "::"
+ │ │ ├── name: :E
+ │ │ ├── delimiter_loc: (4,4)-(4,6) = "::"
+ │ │ └── name_loc: (4,6)-(4,7) = "E"
│ ├── statements:
│ │ @ StatementsNode (location: (5,2)-(5,4))
│ │ └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/const_2_op_asgn_or2.txt b/test/prism/snapshots/seattlerb/const_2_op_asgn_or2.txt
index b018ac48d4..e09eed7d2f 100644
--- a/test/prism/snapshots/seattlerb/const_2_op_asgn_or2.txt
+++ b/test/prism/snapshots/seattlerb/const_2_op_asgn_or2.txt
@@ -9,14 +9,12 @@
│ ├── parent:
│ │ @ ConstantPathNode (location: (1,0)-(1,3))
│ │ ├── parent: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (1,2)-(1,3))
- │ │ │ └── name: :X
- │ │ └── delimiter_loc: (1,0)-(1,2) = "::"
- │ ├── child:
- │ │ @ ConstantReadNode (location: (1,5)-(1,6))
- │ │ └── name: :Y
- │ └── delimiter_loc: (1,3)-(1,5) = "::"
+ │ │ ├── name: :X
+ │ │ ├── delimiter_loc: (1,0)-(1,2) = "::"
+ │ │ └── name_loc: (1,2)-(1,3) = "X"
+ │ ├── name: :Y
+ │ ├── delimiter_loc: (1,3)-(1,5) = "::"
+ │ └── name_loc: (1,5)-(1,6) = "Y"
├── operator_loc: (1,7)-(1,10) = "||="
└── value:
@ IntegerNode (location: (1,11)-(1,12))
diff --git a/test/prism/snapshots/seattlerb/const_3_op_asgn_or.txt b/test/prism/snapshots/seattlerb/const_3_op_asgn_or.txt
index 8d9d94931b..398af888a8 100644
--- a/test/prism/snapshots/seattlerb/const_3_op_asgn_or.txt
+++ b/test/prism/snapshots/seattlerb/const_3_op_asgn_or.txt
@@ -7,10 +7,9 @@
├── target:
│ @ ConstantPathNode (location: (1,0)-(1,3))
│ ├── parent: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (1,2)-(1,3))
- │ │ └── name: :X
- │ └── delimiter_loc: (1,0)-(1,2) = "::"
+ │ ├── name: :X
+ │ ├── delimiter_loc: (1,0)-(1,2) = "::"
+ │ └── name_loc: (1,2)-(1,3) = "X"
├── operator_loc: (1,4)-(1,7) = "||="
└── value:
@ IntegerNode (location: (1,8)-(1,9))
diff --git a/test/prism/snapshots/seattlerb/const_op_asgn_and1.txt b/test/prism/snapshots/seattlerb/const_op_asgn_and1.txt
index b1d61b3752..f9792aebb3 100644
--- a/test/prism/snapshots/seattlerb/const_op_asgn_and1.txt
+++ b/test/prism/snapshots/seattlerb/const_op_asgn_and1.txt
@@ -7,13 +7,12 @@
├── target:
│ @ ConstantPathNode (location: (1,0)-(1,3))
│ ├── parent: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (1,2)-(1,3))
- │ │ └── name: :X
- │ └── delimiter_loc: (1,0)-(1,2) = "::"
- ├── operator_loc: (1,4)-(1,6) = "&="
+ │ ├── name: :X
+ │ ├── delimiter_loc: (1,0)-(1,2) = "::"
+ │ └── name_loc: (1,2)-(1,3) = "X"
+ ├── binary_operator_loc: (1,4)-(1,6) = "&="
├── value:
│ @ IntegerNode (location: (1,7)-(1,8))
│ ├── flags: decimal
│ └── value: 1
- └── operator: :&
+ └── binary_operator: :&
diff --git a/test/prism/snapshots/seattlerb/const_op_asgn_and2.txt b/test/prism/snapshots/seattlerb/const_op_asgn_and2.txt
index 22f6682534..146455d327 100644
--- a/test/prism/snapshots/seattlerb/const_op_asgn_and2.txt
+++ b/test/prism/snapshots/seattlerb/const_op_asgn_and2.txt
@@ -7,10 +7,9 @@
├── target:
│ @ ConstantPathNode (location: (1,0)-(1,3))
│ ├── parent: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (1,2)-(1,3))
- │ │ └── name: :X
- │ └── delimiter_loc: (1,0)-(1,2) = "::"
+ │ ├── name: :X
+ │ ├── delimiter_loc: (1,0)-(1,2) = "::"
+ │ └── name_loc: (1,2)-(1,3) = "X"
├── operator_loc: (1,4)-(1,7) = "&&="
└── value:
@ IntegerNode (location: (1,8)-(1,9))
diff --git a/test/prism/snapshots/seattlerb/const_op_asgn_or.txt b/test/prism/snapshots/seattlerb/const_op_asgn_or.txt
index 067e0fbb93..5e9dd39604 100644
--- a/test/prism/snapshots/seattlerb/const_op_asgn_or.txt
+++ b/test/prism/snapshots/seattlerb/const_op_asgn_or.txt
@@ -9,10 +9,9 @@
│ ├── parent:
│ │ @ ConstantReadNode (location: (1,0)-(1,1))
│ │ └── name: :X
- │ ├── child:
- │ │ @ ConstantReadNode (location: (1,3)-(1,4))
- │ │ └── name: :Y
- │ └── delimiter_loc: (1,1)-(1,3) = "::"
+ │ ├── name: :Y
+ │ ├── delimiter_loc: (1,1)-(1,3) = "::"
+ │ └── name_loc: (1,3)-(1,4) = "Y"
├── operator_loc: (1,5)-(1,8) = "||="
└── value:
@ IntegerNode (location: (1,9)-(1,10))
diff --git a/test/prism/snapshots/seattlerb/defn_kwarg_env.txt b/test/prism/snapshots/seattlerb/defn_kwarg_env.txt
index f420420fc3..2aadedd964 100644
--- a/test/prism/snapshots/seattlerb/defn_kwarg_env.txt
+++ b/test/prism/snapshots/seattlerb/defn_kwarg_env.txt
@@ -33,7 +33,7 @@
│ ├── opening_loc: (1,30)-(1,31) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (1,31)-(1,40))
- │ │ ├── flags: contains_keyword_splat
+ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (1,31)-(1,40))
│ │ ├── flags: ∅
diff --git a/test/prism/snapshots/seattlerb/difficult2_.txt b/test/prism/snapshots/seattlerb/difficult2_.txt
index a9b3736fe3..b53d4cad3f 100644
--- a/test/prism/snapshots/seattlerb/difficult2_.txt
+++ b/test/prism/snapshots/seattlerb/difficult2_.txt
@@ -52,7 +52,7 @@
├── opening_loc: ∅
├── arguments:
│ @ ArgumentsNode (location: (2,2)-(2,6))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (2,2)-(2,6))
│ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/seattlerb/dstr_evstr.txt b/test/prism/snapshots/seattlerb/dstr_evstr.txt
index 8d771e88c2..add8ad6f5c 100644
--- a/test/prism/snapshots/seattlerb/dstr_evstr.txt
+++ b/test/prism/snapshots/seattlerb/dstr_evstr.txt
@@ -13,7 +13,7 @@
│ │ │ @ StatementsNode (location: (1,3)-(1,6))
│ │ │ └── body: (length: 1)
│ │ │ └── @ StringNode (location: (1,3)-(1,6))
- │ │ │ ├── flags: ∅
+ │ │ │ ├── flags: frozen
│ │ │ ├── opening_loc: (1,3)-(1,4) = "'"
│ │ │ ├── content_loc: (1,4)-(1,5) = "a"
│ │ │ ├── closing_loc: (1,5)-(1,6) = "'"
diff --git a/test/prism/snapshots/seattlerb/dstr_str.txt b/test/prism/snapshots/seattlerb/dstr_str.txt
index 70b5752ce3..6fe0781880 100644
--- a/test/prism/snapshots/seattlerb/dstr_str.txt
+++ b/test/prism/snapshots/seattlerb/dstr_str.txt
@@ -4,7 +4,7 @@
@ StatementsNode (location: (1,0)-(1,10))
└── body: (length: 1)
└── @ InterpolatedStringNode (location: (1,0)-(1,10))
- ├── flags: ∅
+ ├── flags: mutable
├── opening_loc: (1,0)-(1,1) = "\""
├── parts: (length: 2)
│ ├── @ EmbeddedStatementsNode (location: (1,1)-(1,7))
@@ -13,7 +13,7 @@
│ │ │ @ StatementsNode (location: (1,3)-(1,6))
│ │ │ └── body: (length: 1)
│ │ │ └── @ StringNode (location: (1,3)-(1,6))
- │ │ │ ├── flags: ∅
+ │ │ │ ├── flags: frozen
│ │ │ ├── opening_loc: (1,3)-(1,4) = "'"
│ │ │ ├── content_loc: (1,4)-(1,5) = "a"
│ │ │ ├── closing_loc: (1,5)-(1,6) = "'"
diff --git a/test/prism/snapshots/seattlerb/heredoc_nested.txt b/test/prism/snapshots/seattlerb/heredoc_nested.txt
index 26d533a33d..a2322b9632 100644
--- a/test/prism/snapshots/seattlerb/heredoc_nested.txt
+++ b/test/prism/snapshots/seattlerb/heredoc_nested.txt
@@ -7,7 +7,7 @@
├── flags: ∅
├── elements: (length: 2)
│ ├── @ InterpolatedStringNode (location: (1,1)-(1,4))
- │ │ ├── flags: ∅
+ │ │ ├── flags: mutable
│ │ ├── opening_loc: (1,1)-(1,4) = "<<A"
│ │ ├── parts: (length: 3)
│ │ │ ├── @ EmbeddedStatementsNode (location: (2,0)-(2,6))
@@ -16,7 +16,7 @@
│ │ │ │ │ @ StatementsNode (location: (2,2)-(2,5))
│ │ │ │ │ └── body: (length: 1)
│ │ │ │ │ └── @ StringNode (location: (2,2)-(2,5))
- │ │ │ │ │ ├── flags: ∅
+ │ │ │ │ │ ├── flags: frozen
│ │ │ │ │ ├── opening_loc: (2,2)-(2,5) = "<<B"
│ │ │ │ │ ├── content_loc: (3,0)-(4,0) = "b\n"
│ │ │ │ │ ├── closing_loc: (4,0)-(5,0) = "B\n"
diff --git a/test/prism/snapshots/seattlerb/index_0_opasgn.txt b/test/prism/snapshots/seattlerb/index_0_opasgn.txt
index 239a549253..322eae9907 100644
--- a/test/prism/snapshots/seattlerb/index_0_opasgn.txt
+++ b/test/prism/snapshots/seattlerb/index_0_opasgn.txt
@@ -21,8 +21,8 @@
├── arguments: ∅
├── closing_loc: (1,2)-(1,3) = "]"
├── block: ∅
- ├── operator: :+
- ├── operator_loc: (1,4)-(1,6) = "+="
+ ├── binary_operator: :+
+ ├── binary_operator_loc: (1,4)-(1,6) = "+="
└── value:
@ CallNode (location: (1,7)-(1,8))
├── flags: variable_call, ignore_visibility
diff --git a/test/prism/snapshots/seattlerb/masgn_colon2.txt b/test/prism/snapshots/seattlerb/masgn_colon2.txt
index 73ce8a71da..a0dfe72ffc 100644
--- a/test/prism/snapshots/seattlerb/masgn_colon2.txt
+++ b/test/prism/snapshots/seattlerb/masgn_colon2.txt
@@ -20,10 +20,9 @@
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (1,6)-(1,7))
- │ │ └── name: :C
- │ └── delimiter_loc: (1,4)-(1,6) = "::"
+ │ ├── name: :C
+ │ ├── delimiter_loc: (1,4)-(1,6) = "::"
+ │ └── name_loc: (1,6)-(1,7) = "C"
├── rest: ∅
├── rights: (length: 0)
├── lparen_loc: ∅
diff --git a/test/prism/snapshots/seattlerb/masgn_colon3.txt b/test/prism/snapshots/seattlerb/masgn_colon3.txt
index 0cf4f8626d..f28ed7ecee 100644
--- a/test/prism/snapshots/seattlerb/masgn_colon3.txt
+++ b/test/prism/snapshots/seattlerb/masgn_colon3.txt
@@ -7,16 +7,14 @@
├── lefts: (length: 2)
│ ├── @ ConstantPathTargetNode (location: (1,0)-(1,3))
│ │ ├── parent: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (1,2)-(1,3))
- │ │ │ └── name: :A
- │ │ └── delimiter_loc: (1,0)-(1,2) = "::"
+ │ │ ├── name: :A
+ │ │ ├── delimiter_loc: (1,0)-(1,2) = "::"
+ │ │ └── name_loc: (1,2)-(1,3) = "A"
│ └── @ ConstantPathTargetNode (location: (1,5)-(1,8))
│ ├── parent: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (1,7)-(1,8))
- │ │ └── name: :B
- │ └── delimiter_loc: (1,5)-(1,7) = "::"
+ │ ├── name: :B
+ │ ├── delimiter_loc: (1,5)-(1,7) = "::"
+ │ └── name_loc: (1,7)-(1,8) = "B"
├── rest: ∅
├── rights: (length: 0)
├── lparen_loc: ∅
diff --git a/test/prism/snapshots/seattlerb/messy_op_asgn_lineno.txt b/test/prism/snapshots/seattlerb/messy_op_asgn_lineno.txt
index 7a3e9affb5..edef23044a 100644
--- a/test/prism/snapshots/seattlerb/messy_op_asgn_lineno.txt
+++ b/test/prism/snapshots/seattlerb/messy_op_asgn_lineno.txt
@@ -24,11 +24,10 @@
│ │ │ ├── parent:
│ │ │ │ @ ConstantReadNode (location: (1,3)-(1,4))
│ │ │ │ └── name: :B
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (1,6)-(1,7))
- │ │ │ │ └── name: :C
- │ │ │ └── delimiter_loc: (1,4)-(1,6) = "::"
- │ │ ├── operator_loc: (1,8)-(1,10) = "*="
+ │ │ │ ├── name: :C
+ │ │ │ ├── delimiter_loc: (1,4)-(1,6) = "::"
+ │ │ │ └── name_loc: (1,6)-(1,7) = "C"
+ │ │ ├── binary_operator_loc: (1,8)-(1,10) = "*="
│ │ ├── value:
│ │ │ @ CallNode (location: (1,11)-(1,14))
│ │ │ ├── flags: ignore_visibility
@@ -53,7 +52,7 @@
│ │ │ │ └── block: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
- │ │ └── operator: :*
+ │ │ └── binary_operator: :*
│ ├── opening_loc: (1,2)-(1,3) = "("
│ └── closing_loc: (1,14)-(1,15) = ")"
├── closing_loc: ∅
diff --git a/test/prism/snapshots/seattlerb/method_call_assoc_trailing_comma.txt b/test/prism/snapshots/seattlerb/method_call_assoc_trailing_comma.txt
index da10a474c3..1bb8bd0bc1 100644
--- a/test/prism/snapshots/seattlerb/method_call_assoc_trailing_comma.txt
+++ b/test/prism/snapshots/seattlerb/method_call_assoc_trailing_comma.txt
@@ -22,7 +22,7 @@
├── opening_loc: (1,3)-(1,4) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,4)-(1,8))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (1,4)-(1,8))
│ ├── flags: ∅
diff --git a/test/prism/snapshots/seattlerb/multiline_hash_declaration.txt b/test/prism/snapshots/seattlerb/multiline_hash_declaration.txt
index 79b0ef5d23..ff28a1798b 100644
--- a/test/prism/snapshots/seattlerb/multiline_hash_declaration.txt
+++ b/test/prism/snapshots/seattlerb/multiline_hash_declaration.txt
@@ -12,7 +12,7 @@
│ ├── opening_loc: (1,1)-(1,2) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (1,2)-(3,1))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (1,2)-(3,1))
│ │ ├── flags: symbol_keys
@@ -42,7 +42,7 @@
│ ├── opening_loc: (5,1)-(5,2) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (5,2)-(6,1))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (5,2)-(6,1))
│ │ ├── flags: symbol_keys
@@ -72,7 +72,7 @@
├── opening_loc: (8,1)-(8,2) = "("
├── arguments:
│ @ ArgumentsNode (location: (8,2)-(8,11))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (8,2)-(8,11))
│ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/seattlerb/op_asgn_primary_colon_const_command_call.txt b/test/prism/snapshots/seattlerb/op_asgn_primary_colon_const_command_call.txt
index 8e6df3e812..523ccde455 100644
--- a/test/prism/snapshots/seattlerb/op_asgn_primary_colon_const_command_call.txt
+++ b/test/prism/snapshots/seattlerb/op_asgn_primary_colon_const_command_call.txt
@@ -9,11 +9,10 @@
│ ├── parent:
│ │ @ ConstantReadNode (location: (1,0)-(1,1))
│ │ └── name: :A
- │ ├── child:
- │ │ @ ConstantReadNode (location: (1,3)-(1,4))
- │ │ └── name: :B
- │ └── delimiter_loc: (1,1)-(1,3) = "::"
- ├── operator_loc: (1,5)-(1,7) = "*="
+ │ ├── name: :B
+ │ ├── delimiter_loc: (1,1)-(1,3) = "::"
+ │ └── name_loc: (1,3)-(1,4) = "B"
+ ├── binary_operator_loc: (1,5)-(1,7) = "*="
├── value:
│ @ CallNode (location: (1,8)-(1,11))
│ ├── flags: ignore_visibility
@@ -38,4 +37,4 @@
│ │ └── block: ∅
│ ├── closing_loc: ∅
│ └── block: ∅
- └── operator: :*
+ └── binary_operator: :*
diff --git a/test/prism/snapshots/seattlerb/op_asgn_primary_colon_identifier1.txt b/test/prism/snapshots/seattlerb/op_asgn_primary_colon_identifier1.txt
index 0daadcf6ff..b9d00edc30 100644
--- a/test/prism/snapshots/seattlerb/op_asgn_primary_colon_identifier1.txt
+++ b/test/prism/snapshots/seattlerb/op_asgn_primary_colon_identifier1.txt
@@ -12,8 +12,8 @@
├── message_loc: (1,3)-(1,4) = "b"
├── read_name: :b
├── write_name: :b=
- ├── operator: :+
- ├── operator_loc: (1,5)-(1,7) = "+="
+ ├── binary_operator: :+
+ ├── binary_operator_loc: (1,5)-(1,7) = "+="
└── value:
@ IntegerNode (location: (1,8)-(1,9))
├── flags: decimal
diff --git a/test/prism/snapshots/seattlerb/op_asgn_primary_colon_identifier_command_call.txt b/test/prism/snapshots/seattlerb/op_asgn_primary_colon_identifier_command_call.txt
index ea8603165b..c12ea3983c 100644
--- a/test/prism/snapshots/seattlerb/op_asgn_primary_colon_identifier_command_call.txt
+++ b/test/prism/snapshots/seattlerb/op_asgn_primary_colon_identifier_command_call.txt
@@ -12,8 +12,8 @@
├── message_loc: (1,3)-(1,4) = "b"
├── read_name: :b
├── write_name: :b=
- ├── operator: :*
- ├── operator_loc: (1,5)-(1,7) = "*="
+ ├── binary_operator: :*
+ ├── binary_operator_loc: (1,5)-(1,7) = "*="
└── value:
@ CallNode (location: (1,8)-(1,11))
├── flags: ignore_visibility
diff --git a/test/prism/snapshots/seattlerb/parse_line_defn_complex.txt b/test/prism/snapshots/seattlerb/parse_line_defn_complex.txt
index 50ccb762be..84eef70b25 100644
--- a/test/prism/snapshots/seattlerb/parse_line_defn_complex.txt
+++ b/test/prism/snapshots/seattlerb/parse_line_defn_complex.txt
@@ -40,15 +40,16 @@
│ │ └── block: ∅
│ ├── @ LocalVariableOperatorWriteNode (location: (3,2)-(3,8))
│ │ ├── name_loc: (3,2)-(3,3) = "y"
- │ │ ├── operator_loc: (3,4)-(3,6) = "*="
+ │ │ ├── binary_operator_loc: (3,4)-(3,6) = "*="
│ │ ├── value:
│ │ │ @ IntegerNode (location: (3,7)-(3,8))
│ │ │ ├── flags: decimal
│ │ │ └── value: 2
│ │ ├── name: :y
- │ │ ├── operator: :*
+ │ │ ├── binary_operator: :*
│ │ └── depth: 0
│ └── @ ReturnNode (location: (4,2)-(4,10))
+ │ ├── flags: redundant
│ ├── keyword_loc: (4,2)-(4,8) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (4,9)-(4,10))
diff --git a/test/prism/snapshots/seattlerb/parse_line_op_asgn.txt b/test/prism/snapshots/seattlerb/parse_line_op_asgn.txt
index 5c2eb2da3c..d113f2af9d 100644
--- a/test/prism/snapshots/seattlerb/parse_line_op_asgn.txt
+++ b/test/prism/snapshots/seattlerb/parse_line_op_asgn.txt
@@ -5,7 +5,7 @@
└── body: (length: 2)
├── @ LocalVariableOperatorWriteNode (location: (1,6)-(2,11))
│ ├── name_loc: (1,6)-(1,9) = "foo"
- │ ├── operator_loc: (1,10)-(1,12) = "+="
+ │ ├── binary_operator_loc: (1,10)-(1,12) = "+="
│ ├── value:
│ │ @ CallNode (location: (2,8)-(2,11))
│ │ ├── flags: variable_call, ignore_visibility
@@ -18,7 +18,7 @@
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── name: :foo
- │ ├── operator: :+
+ │ ├── binary_operator: :+
│ └── depth: 0
└── @ CallNode (location: (3,6)-(3,9))
├── flags: variable_call, ignore_visibility
diff --git a/test/prism/snapshots/seattlerb/parse_line_return.txt b/test/prism/snapshots/seattlerb/parse_line_return.txt
index 9194ae13ee..719a4da5da 100644
--- a/test/prism/snapshots/seattlerb/parse_line_return.txt
+++ b/test/prism/snapshots/seattlerb/parse_line_return.txt
@@ -20,6 +20,7 @@
│ │ @ StatementsNode (location: (3,10)-(3,19))
│ │ └── body: (length: 1)
│ │ └── @ ReturnNode (location: (3,10)-(3,19))
+ │ │ ├── flags: redundant
│ │ ├── keyword_loc: (3,10)-(3,16) = "return"
│ │ └── arguments:
│ │ @ ArgumentsNode (location: (3,17)-(3,19))
diff --git a/test/prism/snapshots/seattlerb/parse_opt_call_args_assocs_comma.txt b/test/prism/snapshots/seattlerb/parse_opt_call_args_assocs_comma.txt
index b767a5c17e..dc11e2ca3d 100644
--- a/test/prism/snapshots/seattlerb/parse_opt_call_args_assocs_comma.txt
+++ b/test/prism/snapshots/seattlerb/parse_opt_call_args_assocs_comma.txt
@@ -15,7 +15,7 @@
├── opening_loc: (1,1)-(1,2) = "["
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(1,6))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (1,2)-(1,6))
│ ├── flags: ∅
diff --git a/test/prism/snapshots/seattlerb/pct_w_heredoc_interp_nested.txt b/test/prism/snapshots/seattlerb/pct_w_heredoc_interp_nested.txt
index c4bc53b723..1b8ec69b56 100644
--- a/test/prism/snapshots/seattlerb/pct_w_heredoc_interp_nested.txt
+++ b/test/prism/snapshots/seattlerb/pct_w_heredoc_interp_nested.txt
@@ -13,7 +13,7 @@
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "1"
│ ├── @ InterpolatedStringNode (location: (1,6)-(1,12))
- │ │ ├── flags: ∅
+ │ │ ├── flags: mutable
│ │ ├── opening_loc: ∅
│ │ ├── parts: (length: 1)
│ │ │ └── @ EmbeddedStatementsNode (location: (1,6)-(1,12))
@@ -22,7 +22,7 @@
│ │ │ │ @ StatementsNode (location: (1,8)-(1,11))
│ │ │ │ └── body: (length: 1)
│ │ │ │ └── @ StringNode (location: (1,8)-(1,11))
- │ │ │ │ ├── flags: ∅
+ │ │ │ │ ├── flags: frozen
│ │ │ │ ├── opening_loc: (1,8)-(1,11) = "<<A"
│ │ │ │ ├── content_loc: (2,0)-(3,0) = "2\n"
│ │ │ │ ├── closing_loc: (3,0)-(4,0) = "A\n"
diff --git a/test/prism/snapshots/seattlerb/quoted_symbol_hash_arg.txt b/test/prism/snapshots/seattlerb/quoted_symbol_hash_arg.txt
index 64caf51bcb..bbc19d50ef 100644
--- a/test/prism/snapshots/seattlerb/quoted_symbol_hash_arg.txt
+++ b/test/prism/snapshots/seattlerb/quoted_symbol_hash_arg.txt
@@ -12,7 +12,7 @@
├── opening_loc: ∅
├── arguments:
│ @ ArgumentsNode (location: (1,5)-(1,12))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (1,5)-(1,12))
│ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/seattlerb/return_call_assocs.txt b/test/prism/snapshots/seattlerb/return_call_assocs.txt
index 69aae7b205..8948f7879b 100644
--- a/test/prism/snapshots/seattlerb/return_call_assocs.txt
+++ b/test/prism/snapshots/seattlerb/return_call_assocs.txt
@@ -4,10 +4,11 @@
@ StatementsNode (location: (1,0)-(11,14))
└── body: (length: 6)
├── @ ReturnNode (location: (1,0)-(1,17))
+ │ ├── flags: ∅
│ ├── keyword_loc: (1,0)-(1,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (1,7)-(1,17))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 2)
│ ├── @ IntegerNode (location: (1,7)-(1,8))
│ │ ├── flags: decimal
@@ -29,10 +30,11 @@
│ │ └── value: 1
│ └── operator_loc: (1,13)-(1,15) = "=>"
├── @ ReturnNode (location: (3,0)-(3,26))
+ │ ├── flags: ∅
│ ├── keyword_loc: (3,0)-(3,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (3,7)-(3,26))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 2)
│ ├── @ IntegerNode (location: (3,7)-(3,8))
│ │ ├── flags: decimal
@@ -67,6 +69,7 @@
│ │ └── value: 2
│ └── operator_loc: (3,22)-(3,24) = "=>"
├── @ ReturnNode (location: (5,0)-(5,14))
+ │ ├── flags: ∅
│ ├── keyword_loc: (5,0)-(5,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (5,7)-(5,14))
@@ -81,7 +84,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (5,9)-(5,14))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (5,9)-(5,14))
│ │ ├── flags: symbol_keys
@@ -102,6 +105,7 @@
│ ├── closing_loc: ∅
│ └── block: ∅
├── @ ReturnNode (location: (7,0)-(7,12))
+ │ ├── flags: ∅
│ ├── keyword_loc: (7,0)-(7,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (7,7)-(7,12))
@@ -116,7 +120,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (7,9)-(7,12))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (7,9)-(7,12))
│ │ ├── flags: symbol_keys
@@ -137,6 +141,7 @@
│ ├── closing_loc: ∅
│ └── block: ∅
├── @ ReturnNode (location: (9,0)-(9,13))
+ │ ├── flags: ∅
│ ├── keyword_loc: (9,0)-(9,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (9,7)-(9,13))
@@ -151,7 +156,7 @@
│ ├── opening_loc: (9,8)-(9,9) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (9,9)-(9,12))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (9,9)-(9,12))
│ │ ├── flags: symbol_keys
@@ -172,6 +177,7 @@
│ ├── closing_loc: (9,12)-(9,13) = ")"
│ └── block: ∅
└── @ ReturnNode (location: (11,0)-(11,14))
+ ├── flags: ∅
├── keyword_loc: (11,0)-(11,6) = "return"
└── arguments:
@ ArgumentsNode (location: (11,7)-(11,14))
@@ -186,7 +192,7 @@
├── opening_loc: (11,8)-(11,9) = "("
├── arguments:
│ @ ArgumentsNode (location: (11,9)-(11,13))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (11,9)-(11,13))
│ ├── flags: ∅
diff --git a/test/prism/snapshots/seattlerb/safe_op_asgn.txt b/test/prism/snapshots/seattlerb/safe_op_asgn.txt
index 7a9fd2b7f7..ebcedd6b5e 100644
--- a/test/prism/snapshots/seattlerb/safe_op_asgn.txt
+++ b/test/prism/snapshots/seattlerb/safe_op_asgn.txt
@@ -20,8 +20,8 @@
├── message_loc: (1,3)-(1,4) = "b"
├── read_name: :b
├── write_name: :b=
- ├── operator: :+
- ├── operator_loc: (1,5)-(1,7) = "+="
+ ├── binary_operator: :+
+ ├── binary_operator_loc: (1,5)-(1,7) = "+="
└── value:
@ CallNode (location: (1,8)-(1,11))
├── flags: ignore_visibility
diff --git a/test/prism/snapshots/seattlerb/str_str.txt b/test/prism/snapshots/seattlerb/str_str.txt
index f3f1213a0c..97031c8a65 100644
--- a/test/prism/snapshots/seattlerb/str_str.txt
+++ b/test/prism/snapshots/seattlerb/str_str.txt
@@ -4,7 +4,7 @@
@ StatementsNode (location: (1,0)-(1,10))
└── body: (length: 1)
└── @ InterpolatedStringNode (location: (1,0)-(1,10))
- ├── flags: ∅
+ ├── flags: mutable
├── opening_loc: (1,0)-(1,1) = "\""
├── parts: (length: 2)
│ ├── @ StringNode (location: (1,1)-(1,3))
@@ -19,7 +19,7 @@
│ │ @ StatementsNode (location: (1,5)-(1,8))
│ │ └── body: (length: 1)
│ │ └── @ StringNode (location: (1,5)-(1,8))
- │ │ ├── flags: ∅
+ │ │ ├── flags: frozen
│ │ ├── opening_loc: (1,5)-(1,6) = "'"
│ │ ├── content_loc: (1,6)-(1,7) = "b"
│ │ ├── closing_loc: (1,7)-(1,8) = "'"
diff --git a/test/prism/snapshots/seattlerb/str_str_str.txt b/test/prism/snapshots/seattlerb/str_str_str.txt
index b01f2b5794..b592d380ef 100644
--- a/test/prism/snapshots/seattlerb/str_str_str.txt
+++ b/test/prism/snapshots/seattlerb/str_str_str.txt
@@ -4,7 +4,7 @@
@ StatementsNode (location: (1,0)-(1,12))
└── body: (length: 1)
└── @ InterpolatedStringNode (location: (1,0)-(1,12))
- ├── flags: ∅
+ ├── flags: mutable
├── opening_loc: (1,0)-(1,1) = "\""
├── parts: (length: 3)
│ ├── @ StringNode (location: (1,1)-(1,3))
@@ -19,7 +19,7 @@
│ │ │ @ StatementsNode (location: (1,5)-(1,8))
│ │ │ └── body: (length: 1)
│ │ │ └── @ StringNode (location: (1,5)-(1,8))
- │ │ │ ├── flags: ∅
+ │ │ │ ├── flags: frozen
│ │ │ ├── opening_loc: (1,5)-(1,6) = "'"
│ │ │ ├── content_loc: (1,6)-(1,7) = "b"
│ │ │ ├── closing_loc: (1,7)-(1,8) = "'"
diff --git a/test/prism/snapshots/unless.txt b/test/prism/snapshots/unless.txt
index 6611ffe63d..6c4aaf66a5 100644
--- a/test/prism/snapshots/unless.txt
+++ b/test/prism/snapshots/unless.txt
@@ -122,6 +122,7 @@
│ │ @ StatementsNode (location: (12,0)-(12,6))
│ │ └── body: (length: 1)
│ │ └── @ ReturnNode (location: (12,0)-(12,6))
+ │ │ ├── flags: ∅
│ │ ├── keyword_loc: (12,0)-(12,6) = "return"
│ │ └── arguments: ∅
│ ├── consequent: ∅
diff --git a/test/prism/snapshots/unparser/corpus/literal/assignment.txt b/test/prism/snapshots/unparser/corpus/literal/assignment.txt
index 99c8daf34c..7d3cc389c6 100644
--- a/test/prism/snapshots/unparser/corpus/literal/assignment.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/assignment.txt
@@ -469,18 +469,16 @@
│ ├── target:
│ │ @ ConstantPathNode (location: (18,0)-(18,5))
│ │ ├── parent: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (18,2)-(18,5))
- │ │ │ └── name: :Foo
- │ │ └── delimiter_loc: (18,0)-(18,2) = "::"
+ │ │ ├── name: :Foo
+ │ │ ├── delimiter_loc: (18,0)-(18,2) = "::"
+ │ │ └── name_loc: (18,2)-(18,5) = "Foo"
│ ├── operator_loc: (18,6)-(18,7) = "="
│ └── value:
│ @ ConstantPathNode (location: (18,8)-(18,13))
│ ├── parent: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (18,10)-(18,13))
- │ │ └── name: :Bar
- │ └── delimiter_loc: (18,8)-(18,10) = "::"
+ │ ├── name: :Bar
+ │ ├── delimiter_loc: (18,8)-(18,10) = "::"
+ │ └── name_loc: (18,10)-(18,13) = "Bar"
├── @ ClassVariableWriteNode (location: (19,0)-(19,7))
│ ├── name: :@@a
│ ├── name_loc: (19,0)-(19,3) = "@@a"
@@ -513,14 +511,12 @@
│ │ │ ├── parent:
│ │ │ │ @ ConstantReadNode (location: (22,0)-(22,4))
│ │ │ │ └── name: :Name
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (22,6)-(22,12))
- │ │ │ │ └── name: :Spaced
- │ │ │ └── delimiter_loc: (22,4)-(22,6) = "::"
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (22,14)-(22,19))
- │ │ │ └── name: :CONST
- │ │ └── delimiter_loc: (22,12)-(22,14) = "::"
+ │ │ │ ├── name: :Spaced
+ │ │ │ ├── delimiter_loc: (22,4)-(22,6) = "::"
+ │ │ │ └── name_loc: (22,6)-(22,12) = "Spaced"
+ │ │ ├── name: :CONST
+ │ │ ├── delimiter_loc: (22,12)-(22,14) = "::"
+ │ │ └── name_loc: (22,14)-(22,19) = "CONST"
│ ├── operator_loc: (22,20)-(22,21) = "="
│ └── value:
│ @ IntegerNode (location: (22,22)-(22,23))
diff --git a/test/prism/snapshots/unparser/corpus/literal/class.txt b/test/prism/snapshots/unparser/corpus/literal/class.txt
index 34eb03edb3..5306888398 100644
--- a/test/prism/snapshots/unparser/corpus/literal/class.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/class.txt
@@ -68,10 +68,9 @@
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (11,6)-(11,7))
│ │ │ └── name: :A
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (11,9)-(11,10))
- │ │ │ └── name: :B
- │ │ └── delimiter_loc: (11,7)-(11,9) = "::"
+ │ │ ├── name: :B
+ │ │ ├── delimiter_loc: (11,7)-(11,9) = "::"
+ │ │ └── name_loc: (11,9)-(11,10) = "B"
│ ├── inheritance_operator_loc: ∅
│ ├── superclass: ∅
│ ├── body: ∅
@@ -87,14 +86,12 @@
│ │ │ ├── parent:
│ │ │ │ @ ConstantReadNode (location: (14,6)-(14,7))
│ │ │ │ └── name: :A
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (14,9)-(14,10))
- │ │ │ │ └── name: :B
- │ │ │ └── delimiter_loc: (14,7)-(14,9) = "::"
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (14,12)-(14,13))
- │ │ │ └── name: :C
- │ │ └── delimiter_loc: (14,10)-(14,12) = "::"
+ │ │ │ ├── name: :B
+ │ │ │ ├── delimiter_loc: (14,7)-(14,9) = "::"
+ │ │ │ └── name_loc: (14,9)-(14,10) = "B"
+ │ │ ├── name: :C
+ │ │ ├── delimiter_loc: (14,10)-(14,12) = "::"
+ │ │ └── name_loc: (14,12)-(14,13) = "C"
│ ├── inheritance_operator_loc: ∅
│ ├── superclass: ∅
│ ├── body: ∅
@@ -125,10 +122,9 @@
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (20,10)-(20,11))
│ │ │ └── name: :B
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (20,13)-(20,14))
- │ │ │ └── name: :C
- │ │ └── delimiter_loc: (20,11)-(20,13) = "::"
+ │ │ ├── name: :C
+ │ │ ├── delimiter_loc: (20,11)-(20,13) = "::"
+ │ │ └── name_loc: (20,13)-(20,14) = "C"
│ ├── body: ∅
│ ├── end_keyword_loc: (21,0)-(21,3) = "end"
│ └── name: :A
@@ -140,20 +136,18 @@
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (23,6)-(23,7))
│ │ │ └── name: :A
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (23,9)-(23,10))
- │ │ │ └── name: :B
- │ │ └── delimiter_loc: (23,7)-(23,9) = "::"
+ │ │ ├── name: :B
+ │ │ ├── delimiter_loc: (23,7)-(23,9) = "::"
+ │ │ └── name_loc: (23,9)-(23,10) = "B"
│ ├── inheritance_operator_loc: (23,11)-(23,12) = "<"
│ ├── superclass:
│ │ @ ConstantPathNode (location: (23,13)-(23,17))
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (23,13)-(23,14))
│ │ │ └── name: :C
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (23,16)-(23,17))
- │ │ │ └── name: :D
- │ │ └── delimiter_loc: (23,14)-(23,16) = "::"
+ │ │ ├── name: :D
+ │ │ ├── delimiter_loc: (23,14)-(23,16) = "::"
+ │ │ └── name_loc: (23,16)-(23,17) = "D"
│ ├── body: ∅
│ ├── end_keyword_loc: (24,0)-(24,3) = "end"
│ └── name: :B
@@ -222,10 +216,9 @@
├── constant_path:
│ @ ConstantPathNode (location: (34,6)-(34,9))
│ ├── parent: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (34,8)-(34,9))
- │ │ └── name: :A
- │ └── delimiter_loc: (34,6)-(34,8) = "::"
+ │ ├── name: :A
+ │ ├── delimiter_loc: (34,6)-(34,8) = "::"
+ │ └── name_loc: (34,8)-(34,9) = "A"
├── inheritance_operator_loc: ∅
├── superclass: ∅
├── body: ∅
diff --git a/test/prism/snapshots/unparser/corpus/literal/defs.txt b/test/prism/snapshots/unparser/corpus/literal/defs.txt
index 431843cc19..7858877172 100644
--- a/test/prism/snapshots/unparser/corpus/literal/defs.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/defs.txt
@@ -225,10 +225,9 @@
│ │ │ │ ├── parent:
│ │ │ │ │ @ ConstantReadNode (location: (26,5)-(26,8))
│ │ │ │ │ └── name: :Foo
- │ │ │ │ ├── child:
- │ │ │ │ │ @ ConstantReadNode (location: (26,10)-(26,13))
- │ │ │ │ │ └── name: :Bar
- │ │ │ │ └── delimiter_loc: (26,8)-(26,10) = "::"
+ │ │ │ │ ├── name: :Bar
+ │ │ │ │ ├── delimiter_loc: (26,8)-(26,10) = "::"
+ │ │ │ │ └── name_loc: (26,10)-(26,13) = "Bar"
│ │ │ ├── call_operator_loc: (26,13)-(26,14) = "."
│ │ │ ├── name: :baz
│ │ │ ├── message_loc: (26,14)-(26,17) = "baz"
@@ -269,10 +268,9 @@
│ │ │ ├── parent:
│ │ │ │ @ ConstantReadNode (location: (30,5)-(30,8))
│ │ │ │ └── name: :Foo
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (30,10)-(30,13))
- │ │ │ │ └── name: :Bar
- │ │ │ └── delimiter_loc: (30,8)-(30,10) = "::"
+ │ │ │ ├── name: :Bar
+ │ │ │ ├── delimiter_loc: (30,8)-(30,10) = "::"
+ │ │ │ └── name_loc: (30,10)-(30,13) = "Bar"
│ │ ├── opening_loc: (30,4)-(30,5) = "("
│ │ └── closing_loc: (30,13)-(30,14) = ")"
│ ├── parameters: ∅
diff --git a/test/prism/snapshots/unparser/corpus/literal/dstr.txt b/test/prism/snapshots/unparser/corpus/literal/dstr.txt
index e60a309b34..8893e8b75d 100644
--- a/test/prism/snapshots/unparser/corpus/literal/dstr.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/dstr.txt
@@ -203,6 +203,7 @@
│ │ @ StatementsNode (location: (27,2)-(27,19))
│ │ └── body: (length: 1)
│ │ └── @ ReturnNode (location: (27,2)-(27,19))
+ │ │ ├── flags: ∅
│ │ ├── keyword_loc: (27,2)-(27,8) = "return"
│ │ └── arguments:
│ │ @ ArgumentsNode (location: (27,9)-(27,19))
diff --git a/test/prism/snapshots/unparser/corpus/literal/literal.txt b/test/prism/snapshots/unparser/corpus/literal/literal.txt
index dcf00bf4e0..98b88e11ce 100644
--- a/test/prism/snapshots/unparser/corpus/literal/literal.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/literal.txt
@@ -635,7 +635,7 @@
│ │ │ @ StatementsNode (location: (53,3)-(53,11))
│ │ │ └── body: (length: 1)
│ │ │ └── @ StringNode (location: (53,3)-(53,11))
- │ │ │ ├── flags: ∅
+ │ │ │ ├── flags: frozen
│ │ │ ├── opening_loc: (53,3)-(53,4) = "\""
│ │ │ ├── content_loc: (53,4)-(53,10) = "\\u0000"
│ │ │ ├── closing_loc: (53,10)-(53,11) = "\""
@@ -707,7 +707,7 @@
│ │ │ @ StatementsNode (location: (59,4)-(59,9))
│ │ │ └── body: (length: 1)
│ │ │ └── @ StringNode (location: (59,4)-(59,9))
- │ │ │ ├── flags: ∅
+ │ │ │ ├── flags: frozen
│ │ │ ├── opening_loc: (59,4)-(59,5) = "\""
│ │ │ ├── content_loc: (59,5)-(59,8) = "foo"
│ │ │ ├── closing_loc: (59,8)-(59,9) = "\""
diff --git a/test/prism/snapshots/unparser/corpus/literal/module.txt b/test/prism/snapshots/unparser/corpus/literal/module.txt
index 5dd8c03b51..6428aeea82 100644
--- a/test/prism/snapshots/unparser/corpus/literal/module.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/module.txt
@@ -20,10 +20,9 @@
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (4,7)-(4,8))
│ │ │ └── name: :A
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (4,10)-(4,11))
- │ │ │ └── name: :B
- │ │ └── delimiter_loc: (4,8)-(4,10) = "::"
+ │ │ ├── name: :B
+ │ │ ├── delimiter_loc: (4,8)-(4,10) = "::"
+ │ │ └── name_loc: (4,10)-(4,11) = "B"
│ ├── body: ∅
│ ├── end_keyword_loc: (5,0)-(5,3) = "end"
│ └── name: :B
@@ -37,14 +36,12 @@
│ │ │ ├── parent:
│ │ │ │ @ ConstantReadNode (location: (7,7)-(7,8))
│ │ │ │ └── name: :A
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (7,10)-(7,11))
- │ │ │ │ └── name: :B
- │ │ │ └── delimiter_loc: (7,8)-(7,10) = "::"
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (7,13)-(7,14))
- │ │ │ └── name: :C
- │ │ └── delimiter_loc: (7,11)-(7,13) = "::"
+ │ │ │ ├── name: :B
+ │ │ │ ├── delimiter_loc: (7,8)-(7,10) = "::"
+ │ │ │ └── name_loc: (7,10)-(7,11) = "B"
+ │ │ ├── name: :C
+ │ │ ├── delimiter_loc: (7,11)-(7,13) = "::"
+ │ │ └── name_loc: (7,13)-(7,14) = "C"
│ ├── body: ∅
│ ├── end_keyword_loc: (8,0)-(8,3) = "end"
│ └── name: :C
diff --git a/test/prism/snapshots/unparser/corpus/literal/opasgn.txt b/test/prism/snapshots/unparser/corpus/literal/opasgn.txt
index 8dc0849638..0761b47348 100644
--- a/test/prism/snapshots/unparser/corpus/literal/opasgn.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/opasgn.txt
@@ -5,53 +5,53 @@
└── body: (length: 24)
├── @ LocalVariableOperatorWriteNode (location: (1,0)-(1,6))
│ ├── name_loc: (1,0)-(1,1) = "a"
- │ ├── operator_loc: (1,2)-(1,4) = "+="
+ │ ├── binary_operator_loc: (1,2)-(1,4) = "+="
│ ├── value:
│ │ @ IntegerNode (location: (1,5)-(1,6))
│ │ ├── flags: decimal
│ │ └── value: 2
│ ├── name: :a
- │ ├── operator: :+
+ │ ├── binary_operator: :+
│ └── depth: 0
├── @ LocalVariableOperatorWriteNode (location: (2,0)-(2,6))
│ ├── name_loc: (2,0)-(2,1) = "a"
- │ ├── operator_loc: (2,2)-(2,4) = "-="
+ │ ├── binary_operator_loc: (2,2)-(2,4) = "-="
│ ├── value:
│ │ @ IntegerNode (location: (2,5)-(2,6))
│ │ ├── flags: decimal
│ │ └── value: 2
│ ├── name: :a
- │ ├── operator: :-
+ │ ├── binary_operator: :-
│ └── depth: 0
├── @ LocalVariableOperatorWriteNode (location: (3,0)-(3,7))
│ ├── name_loc: (3,0)-(3,1) = "a"
- │ ├── operator_loc: (3,2)-(3,5) = "**="
+ │ ├── binary_operator_loc: (3,2)-(3,5) = "**="
│ ├── value:
│ │ @ IntegerNode (location: (3,6)-(3,7))
│ │ ├── flags: decimal
│ │ └── value: 2
│ ├── name: :a
- │ ├── operator: :**
+ │ ├── binary_operator: :**
│ └── depth: 0
├── @ LocalVariableOperatorWriteNode (location: (4,0)-(4,6))
│ ├── name_loc: (4,0)-(4,1) = "a"
- │ ├── operator_loc: (4,2)-(4,4) = "*="
+ │ ├── binary_operator_loc: (4,2)-(4,4) = "*="
│ ├── value:
│ │ @ IntegerNode (location: (4,5)-(4,6))
│ │ ├── flags: decimal
│ │ └── value: 2
│ ├── name: :a
- │ ├── operator: :*
+ │ ├── binary_operator: :*
│ └── depth: 0
├── @ LocalVariableOperatorWriteNode (location: (5,0)-(5,6))
│ ├── name_loc: (5,0)-(5,1) = "a"
- │ ├── operator_loc: (5,2)-(5,4) = "/="
+ │ ├── binary_operator_loc: (5,2)-(5,4) = "/="
│ ├── value:
│ │ @ IntegerNode (location: (5,5)-(5,6))
│ │ ├── flags: decimal
│ │ └── value: 2
│ ├── name: :a
- │ ├── operator: :/
+ │ ├── binary_operator: :/
│ └── depth: 0
├── @ LocalVariableAndWriteNode (location: (6,0)-(6,7))
│ ├── name_loc: (6,0)-(6,1) = "a"
@@ -162,8 +162,8 @@
│ ├── message_loc: (10,2)-(10,3) = "b"
│ ├── read_name: :b
│ ├── write_name: :b=
- │ ├── operator: :+
- │ ├── operator_loc: (10,4)-(10,6) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (10,4)-(10,6) = "+="
│ └── value:
│ @ IntegerNode (location: (10,7)-(10,8))
│ ├── flags: decimal
@@ -178,8 +178,8 @@
│ ├── message_loc: (11,2)-(11,3) = "b"
│ ├── read_name: :b
│ ├── write_name: :b=
- │ ├── operator: :-
- │ ├── operator_loc: (11,4)-(11,6) = "-="
+ │ ├── binary_operator: :-
+ │ ├── binary_operator_loc: (11,4)-(11,6) = "-="
│ └── value:
│ @ IntegerNode (location: (11,7)-(11,8))
│ ├── flags: decimal
@@ -194,8 +194,8 @@
│ ├── message_loc: (12,2)-(12,3) = "b"
│ ├── read_name: :b
│ ├── write_name: :b=
- │ ├── operator: :**
- │ ├── operator_loc: (12,4)-(12,7) = "**="
+ │ ├── binary_operator: :**
+ │ ├── binary_operator_loc: (12,4)-(12,7) = "**="
│ └── value:
│ @ IntegerNode (location: (12,8)-(12,9))
│ ├── flags: decimal
@@ -210,8 +210,8 @@
│ ├── message_loc: (13,2)-(13,3) = "b"
│ ├── read_name: :b
│ ├── write_name: :b=
- │ ├── operator: :*
- │ ├── operator_loc: (13,4)-(13,6) = "*="
+ │ ├── binary_operator: :*
+ │ ├── binary_operator_loc: (13,4)-(13,6) = "*="
│ └── value:
│ @ IntegerNode (location: (13,7)-(13,8))
│ ├── flags: decimal
@@ -226,8 +226,8 @@
│ ├── message_loc: (14,2)-(14,3) = "b"
│ ├── read_name: :b
│ ├── write_name: :b=
- │ ├── operator: :/
- │ ├── operator_loc: (14,4)-(14,6) = "/="
+ │ ├── binary_operator: :/
+ │ ├── binary_operator_loc: (14,4)-(14,6) = "/="
│ └── value:
│ @ IntegerNode (location: (14,7)-(14,8))
│ ├── flags: decimal
@@ -293,8 +293,8 @@
│ │ └── block: ∅
│ ├── closing_loc: (17,3)-(17,4) = "]"
│ ├── block: ∅
- │ ├── operator: :+
- │ ├── operator_loc: (17,5)-(17,7) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (17,5)-(17,7) = "+="
│ └── value:
│ @ IntegerNode (location: (17,8)-(17,9))
│ ├── flags: decimal
@@ -323,8 +323,8 @@
│ │ └── block: ∅
│ ├── closing_loc: (18,3)-(18,4) = "]"
│ ├── block: ∅
- │ ├── operator: :-
- │ ├── operator_loc: (18,5)-(18,7) = "-="
+ │ ├── binary_operator: :-
+ │ ├── binary_operator_loc: (18,5)-(18,7) = "-="
│ └── value:
│ @ IntegerNode (location: (18,8)-(18,9))
│ ├── flags: decimal
@@ -353,8 +353,8 @@
│ │ └── block: ∅
│ ├── closing_loc: (19,3)-(19,4) = "]"
│ ├── block: ∅
- │ ├── operator: :**
- │ ├── operator_loc: (19,5)-(19,8) = "**="
+ │ ├── binary_operator: :**
+ │ ├── binary_operator_loc: (19,5)-(19,8) = "**="
│ └── value:
│ @ IntegerNode (location: (19,9)-(19,10))
│ ├── flags: decimal
@@ -383,8 +383,8 @@
│ │ └── block: ∅
│ ├── closing_loc: (20,3)-(20,4) = "]"
│ ├── block: ∅
- │ ├── operator: :*
- │ ├── operator_loc: (20,5)-(20,7) = "*="
+ │ ├── binary_operator: :*
+ │ ├── binary_operator_loc: (20,5)-(20,7) = "*="
│ └── value:
│ @ IntegerNode (location: (20,8)-(20,9))
│ ├── flags: decimal
@@ -413,8 +413,8 @@
│ │ └── block: ∅
│ ├── closing_loc: (21,3)-(21,4) = "]"
│ ├── block: ∅
- │ ├── operator: :/
- │ ├── operator_loc: (21,5)-(21,7) = "/="
+ │ ├── binary_operator: :/
+ │ ├── binary_operator_loc: (21,5)-(21,7) = "/="
│ └── value:
│ @ IntegerNode (location: (21,8)-(21,9))
│ ├── flags: decimal
@@ -501,8 +501,8 @@
├── message_loc: (24,4)-(24,5) = "A"
├── read_name: :A
├── write_name: :A=
- ├── operator: :+
- ├── operator_loc: (24,6)-(24,8) = "+="
+ ├── binary_operator: :+
+ ├── binary_operator_loc: (24,6)-(24,8) = "+="
└── value:
@ IntegerNode (location: (24,9)-(24,10))
├── flags: decimal
diff --git a/test/prism/snapshots/unparser/corpus/literal/rescue.txt b/test/prism/snapshots/unparser/corpus/literal/rescue.txt
index d84366f3f5..d3c9d62166 100644
--- a/test/prism/snapshots/unparser/corpus/literal/rescue.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/rescue.txt
@@ -42,6 +42,7 @@
│ ├── keyword_loc: (2,4)-(2,10) = "rescue"
│ └── rescue_expression:
│ @ ReturnNode (location: (2,11)-(2,21))
+ │ ├── flags: ∅
│ ├── keyword_loc: (2,11)-(2,17) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (2,18)-(2,21))
@@ -81,6 +82,7 @@
│ │ ├── keyword_loc: (3,9)-(3,15) = "rescue"
│ │ └── rescue_expression:
│ │ @ ReturnNode (location: (3,16)-(3,26))
+ │ │ ├── flags: ∅
│ │ ├── keyword_loc: (3,16)-(3,22) = "return"
│ │ └── arguments:
│ │ @ ArgumentsNode (location: (3,23)-(3,26))
diff --git a/test/prism/snapshots/unparser/corpus/literal/send.txt b/test/prism/snapshots/unparser/corpus/literal/send.txt
index b7eb064717..3fd7f719a1 100644
--- a/test/prism/snapshots/unparser/corpus/literal/send.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/send.txt
@@ -1251,7 +1251,7 @@
│ ├── opening_loc: (63,7)-(63,8) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (63,8)-(63,16))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (63,8)-(63,16))
│ │ ├── flags: symbol_keys
@@ -1297,7 +1297,7 @@
│ ├── opening_loc: (64,7)-(64,8) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (64,8)-(64,25))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 2)
│ │ ├── @ CallNode (location: (64,8)-(64,11))
│ │ │ ├── flags: variable_call, ignore_visibility
@@ -1571,7 +1571,7 @@
│ ├── opening_loc: (70,3)-(70,4) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (70,4)-(70,8))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (70,4)-(70,8))
│ │ ├── flags: symbol_keys
@@ -1617,7 +1617,7 @@
│ ├── opening_loc: (71,5)-(71,6) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (71,6)-(71,10))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (71,6)-(71,10))
│ │ ├── flags: symbol_keys
@@ -1663,7 +1663,7 @@
│ ├── opening_loc: (72,5)-(72,6) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (72,6)-(72,9))
- │ │ ├── flags: contains_keyword_splat
+ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (72,6)-(72,9))
│ │ ├── flags: ∅
@@ -2082,7 +2082,7 @@
│ ├── opening_loc: (81,1)-(81,2) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (81,2)-(81,7))
- │ │ ├── flags: contains_keyword_splat
+ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (81,2)-(81,7))
│ │ ├── flags: ∅
diff --git a/test/prism/snapshots/unparser/corpus/literal/since/32.txt b/test/prism/snapshots/unparser/corpus/literal/since/32.txt
index e72be6d8b7..2b28be2fa8 100644
--- a/test/prism/snapshots/unparser/corpus/literal/since/32.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/since/32.txt
@@ -36,7 +36,7 @@
│ │ ├── opening_loc: (2,5)-(2,6) = "("
│ │ ├── arguments:
│ │ │ @ ArgumentsNode (location: (2,6)-(2,18))
- │ │ │ ├── flags: contains_keyword_splat
+ │ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ │ └── arguments: (length: 2)
│ │ │ ├── @ LocalVariableReadNode (location: (2,6)-(2,14))
│ │ │ │ ├── name: :argument
diff --git a/test/prism/snapshots/unparser/corpus/literal/variables.txt b/test/prism/snapshots/unparser/corpus/literal/variables.txt
index bf79de385c..9ae8ad1207 100644
--- a/test/prism/snapshots/unparser/corpus/literal/variables.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/variables.txt
@@ -29,25 +29,21 @@
│ ├── parent:
│ │ @ ConstantReadNode (location: (8,0)-(8,6))
│ │ └── name: :SCOPED
- │ ├── child:
- │ │ @ ConstantReadNode (location: (8,8)-(8,13))
- │ │ └── name: :CONST
- │ └── delimiter_loc: (8,6)-(8,8) = "::"
+ │ ├── name: :CONST
+ │ ├── delimiter_loc: (8,6)-(8,8) = "::"
+ │ └── name_loc: (8,8)-(8,13) = "CONST"
├── @ ConstantPathNode (location: (9,0)-(9,10))
│ ├── parent: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (9,2)-(9,10))
- │ │ └── name: :TOPLEVEL
- │ └── delimiter_loc: (9,0)-(9,2) = "::"
+ │ ├── name: :TOPLEVEL
+ │ ├── delimiter_loc: (9,0)-(9,2) = "::"
+ │ └── name_loc: (9,2)-(9,10) = "TOPLEVEL"
└── @ ConstantPathNode (location: (10,0)-(10,17))
├── parent:
│ @ ConstantPathNode (location: (10,0)-(10,10))
│ ├── parent: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (10,2)-(10,10))
- │ │ └── name: :TOPLEVEL
- │ └── delimiter_loc: (10,0)-(10,2) = "::"
- ├── child:
- │ @ ConstantReadNode (location: (10,12)-(10,17))
- │ └── name: :CONST
- └── delimiter_loc: (10,10)-(10,12) = "::"
+ │ ├── name: :TOPLEVEL
+ │ ├── delimiter_loc: (10,0)-(10,2) = "::"
+ │ └── name_loc: (10,2)-(10,10) = "TOPLEVEL"
+ ├── name: :CONST
+ ├── delimiter_loc: (10,10)-(10,12) = "::"
+ └── name_loc: (10,12)-(10,17) = "CONST"
diff --git a/test/prism/snapshots/unparser/corpus/semantic/opasgn.txt b/test/prism/snapshots/unparser/corpus/semantic/opasgn.txt
index e100dd8ecb..7dd26a38dc 100644
--- a/test/prism/snapshots/unparser/corpus/semantic/opasgn.txt
+++ b/test/prism/snapshots/unparser/corpus/semantic/opasgn.txt
@@ -44,8 +44,8 @@
│ └── closing_loc: (1,10)-(1,11) = "\""
├── closing_loc: (1,11)-(1,12) = "]"
├── block: ∅
- ├── operator: :+
- ├── operator_loc: (1,13)-(1,15) = "+="
+ ├── binary_operator: :+
+ ├── binary_operator_loc: (1,13)-(1,15) = "+="
└── value:
@ InterpolatedStringNode (location: (1,16)-(1,25))
├── flags: ∅
diff --git a/test/prism/snapshots/until.txt b/test/prism/snapshots/until.txt
index d45e39644b..e855dc89f7 100644
--- a/test/prism/snapshots/until.txt
+++ b/test/prism/snapshots/until.txt
@@ -97,6 +97,7 @@
│ @ StatementsNode (location: (9,0)-(9,6))
│ └── body: (length: 1)
│ └── @ ReturnNode (location: (9,0)-(9,6))
+ │ ├── flags: ∅
│ ├── keyword_loc: (9,0)-(9,6) = "return"
│ └── arguments: ∅
├── @ UntilNode (location: (11,0)-(11,21))
diff --git a/test/prism/snapshots/while.txt b/test/prism/snapshots/while.txt
index 36fab49960..a2972face0 100644
--- a/test/prism/snapshots/while.txt
+++ b/test/prism/snapshots/while.txt
@@ -97,6 +97,7 @@
│ @ StatementsNode (location: (9,0)-(9,6))
│ └── body: (length: 1)
│ └── @ ReturnNode (location: (9,0)-(9,6))
+ │ ├── flags: ∅
│ ├── keyword_loc: (9,0)-(9,6) = "return"
│ └── arguments: ∅
├── @ WhileNode (location: (11,0)-(11,21))
diff --git a/test/prism/snapshots/whitequark/args_args_assocs.txt b/test/prism/snapshots/whitequark/args_args_assocs.txt
index 6297f212d8..d257a885ce 100644
--- a/test/prism/snapshots/whitequark/args_args_assocs.txt
+++ b/test/prism/snapshots/whitequark/args_args_assocs.txt
@@ -12,7 +12,7 @@
│ ├── opening_loc: (1,3)-(1,4) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (1,4)-(1,18))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 2)
│ │ ├── @ CallNode (location: (1,4)-(1,7))
│ │ │ ├── flags: variable_call, ignore_visibility
@@ -51,7 +51,7 @@
├── opening_loc: (3,3)-(3,4) = "("
├── arguments:
│ @ ArgumentsNode (location: (3,4)-(3,18))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 2)
│ ├── @ CallNode (location: (3,4)-(3,7))
│ │ ├── flags: variable_call, ignore_visibility
diff --git a/test/prism/snapshots/whitequark/args_args_assocs_comma.txt b/test/prism/snapshots/whitequark/args_args_assocs_comma.txt
index 969514a511..2d986dd90a 100644
--- a/test/prism/snapshots/whitequark/args_args_assocs_comma.txt
+++ b/test/prism/snapshots/whitequark/args_args_assocs_comma.txt
@@ -22,7 +22,7 @@
├── opening_loc: (1,3)-(1,4) = "["
├── arguments:
│ @ ArgumentsNode (location: (1,4)-(1,18))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 2)
│ ├── @ CallNode (location: (1,4)-(1,7))
│ │ ├── flags: variable_call, ignore_visibility
diff --git a/test/prism/snapshots/whitequark/args_assocs_comma.txt b/test/prism/snapshots/whitequark/args_assocs_comma.txt
index b1b9fbeefe..64a25bbc45 100644
--- a/test/prism/snapshots/whitequark/args_assocs_comma.txt
+++ b/test/prism/snapshots/whitequark/args_assocs_comma.txt
@@ -22,7 +22,7 @@
├── opening_loc: (1,3)-(1,4) = "["
├── arguments:
│ @ ArgumentsNode (location: (1,4)-(1,13))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (1,4)-(1,13))
│ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/whitequark/bug_cmdarg.txt b/test/prism/snapshots/whitequark/bug_cmdarg.txt
index 509dd7e818..32d05746a7 100644
--- a/test/prism/snapshots/whitequark/bug_cmdarg.txt
+++ b/test/prism/snapshots/whitequark/bug_cmdarg.txt
@@ -12,7 +12,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (1,7)-(1,15))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (1,7)-(1,15))
│ │ ├── flags: symbol_keys
@@ -62,7 +62,7 @@
├── opening_loc: ∅
├── arguments:
│ @ ArgumentsNode (location: (5,2)-(5,26))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (5,2)-(5,26))
│ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/whitequark/casgn_scoped.txt b/test/prism/snapshots/whitequark/casgn_scoped.txt
index 4e3fd6fe44..42b90be061 100644
--- a/test/prism/snapshots/whitequark/casgn_scoped.txt
+++ b/test/prism/snapshots/whitequark/casgn_scoped.txt
@@ -9,10 +9,9 @@
│ ├── parent:
│ │ @ ConstantReadNode (location: (1,0)-(1,3))
│ │ └── name: :Bar
- │ ├── child:
- │ │ @ ConstantReadNode (location: (1,5)-(1,8))
- │ │ └── name: :Foo
- │ └── delimiter_loc: (1,3)-(1,5) = "::"
+ │ ├── name: :Foo
+ │ ├── delimiter_loc: (1,3)-(1,5) = "::"
+ │ └── name_loc: (1,5)-(1,8) = "Foo"
├── operator_loc: (1,9)-(1,10) = "="
└── value:
@ IntegerNode (location: (1,11)-(1,13))
diff --git a/test/prism/snapshots/whitequark/casgn_toplevel.txt b/test/prism/snapshots/whitequark/casgn_toplevel.txt
index 11facfefb3..070d90a46b 100644
--- a/test/prism/snapshots/whitequark/casgn_toplevel.txt
+++ b/test/prism/snapshots/whitequark/casgn_toplevel.txt
@@ -7,10 +7,9 @@
├── target:
│ @ ConstantPathNode (location: (1,0)-(1,5))
│ ├── parent: ∅
- │ ├── child:
- │ │ @ ConstantReadNode (location: (1,2)-(1,5))
- │ │ └── name: :Foo
- │ └── delimiter_loc: (1,0)-(1,2) = "::"
+ │ ├── name: :Foo
+ │ ├── delimiter_loc: (1,0)-(1,2) = "::"
+ │ └── name_loc: (1,2)-(1,5) = "Foo"
├── operator_loc: (1,6)-(1,7) = "="
└── value:
@ IntegerNode (location: (1,8)-(1,10))
diff --git a/test/prism/snapshots/whitequark/const_op_asgn.txt b/test/prism/snapshots/whitequark/const_op_asgn.txt
index 4985f3e54b..71df6208d2 100644
--- a/test/prism/snapshots/whitequark/const_op_asgn.txt
+++ b/test/prism/snapshots/whitequark/const_op_asgn.txt
@@ -7,41 +7,39 @@
│ ├── target:
│ │ @ ConstantPathNode (location: (1,0)-(1,3))
│ │ ├── parent: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (1,2)-(1,3))
- │ │ │ └── name: :A
- │ │ └── delimiter_loc: (1,0)-(1,2) = "::"
- │ ├── operator_loc: (1,4)-(1,6) = "+="
+ │ │ ├── name: :A
+ │ │ ├── delimiter_loc: (1,0)-(1,2) = "::"
+ │ │ └── name_loc: (1,2)-(1,3) = "A"
+ │ ├── binary_operator_loc: (1,4)-(1,6) = "+="
│ ├── value:
│ │ @ IntegerNode (location: (1,7)-(1,8))
│ │ ├── flags: decimal
│ │ └── value: 1
- │ └── operator: :+
+ │ └── binary_operator: :+
├── @ ConstantOperatorWriteNode (location: (3,0)-(3,6))
│ ├── name: :A
│ ├── name_loc: (3,0)-(3,1) = "A"
- │ ├── operator_loc: (3,2)-(3,4) = "+="
+ │ ├── binary_operator_loc: (3,2)-(3,4) = "+="
│ ├── value:
│ │ @ IntegerNode (location: (3,5)-(3,6))
│ │ ├── flags: decimal
│ │ └── value: 1
- │ └── operator: :+
+ │ └── binary_operator: :+
├── @ ConstantPathOperatorWriteNode (location: (5,0)-(5,9))
│ ├── target:
│ │ @ ConstantPathNode (location: (5,0)-(5,4))
│ │ ├── parent:
│ │ │ @ ConstantReadNode (location: (5,0)-(5,1))
│ │ │ └── name: :B
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (5,3)-(5,4))
- │ │ │ └── name: :A
- │ │ └── delimiter_loc: (5,1)-(5,3) = "::"
- │ ├── operator_loc: (5,5)-(5,7) = "+="
+ │ │ ├── name: :A
+ │ │ ├── delimiter_loc: (5,1)-(5,3) = "::"
+ │ │ └── name_loc: (5,3)-(5,4) = "A"
+ │ ├── binary_operator_loc: (5,5)-(5,7) = "+="
│ ├── value:
│ │ @ IntegerNode (location: (5,8)-(5,9))
│ │ ├── flags: decimal
│ │ └── value: 1
- │ └── operator: :+
+ │ └── binary_operator: :+
├── @ DefNode (location: (7,0)-(7,21))
│ ├── name: :x
│ ├── name_loc: (7,4)-(7,5) = "x"
@@ -54,10 +52,9 @@
│ │ ├── target:
│ │ │ @ ConstantPathNode (location: (7,7)-(7,10))
│ │ │ ├── parent: ∅
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (7,9)-(7,10))
- │ │ │ │ └── name: :A
- │ │ │ └── delimiter_loc: (7,7)-(7,9) = "::"
+ │ │ │ ├── name: :A
+ │ │ │ ├── delimiter_loc: (7,7)-(7,9) = "::"
+ │ │ │ └── name_loc: (7,9)-(7,10) = "A"
│ │ ├── operator_loc: (7,11)-(7,14) = "||="
│ │ └── value:
│ │ @ IntegerNode (location: (7,15)-(7,16))
@@ -83,10 +80,9 @@
│ │ @ ConstantPathNode (location: (9,7)-(9,14))
│ │ ├── parent:
│ │ │ @ SelfNode (location: (9,7)-(9,11))
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (9,13)-(9,14))
- │ │ │ └── name: :A
- │ │ └── delimiter_loc: (9,11)-(9,13) = "::"
+ │ │ ├── name: :A
+ │ │ ├── delimiter_loc: (9,11)-(9,13) = "::"
+ │ │ └── name_loc: (9,13)-(9,14) = "A"
│ ├── operator_loc: (9,15)-(9,18) = "||="
│ └── value:
│ @ IntegerNode (location: (9,19)-(9,20))
diff --git a/test/prism/snapshots/whitequark/const_scoped.txt b/test/prism/snapshots/whitequark/const_scoped.txt
index 1e2bccef96..83af4b187b 100644
--- a/test/prism/snapshots/whitequark/const_scoped.txt
+++ b/test/prism/snapshots/whitequark/const_scoped.txt
@@ -7,7 +7,6 @@
├── parent:
│ @ ConstantReadNode (location: (1,0)-(1,3))
│ └── name: :Bar
- ├── child:
- │ @ ConstantReadNode (location: (1,5)-(1,8))
- │ └── name: :Foo
- └── delimiter_loc: (1,3)-(1,5) = "::"
+ ├── name: :Foo
+ ├── delimiter_loc: (1,3)-(1,5) = "::"
+ └── name_loc: (1,5)-(1,8) = "Foo"
diff --git a/test/prism/snapshots/whitequark/const_toplevel.txt b/test/prism/snapshots/whitequark/const_toplevel.txt
index b54b069d06..3d7df5defc 100644
--- a/test/prism/snapshots/whitequark/const_toplevel.txt
+++ b/test/prism/snapshots/whitequark/const_toplevel.txt
@@ -5,7 +5,6 @@
└── body: (length: 1)
└── @ ConstantPathNode (location: (1,0)-(1,5))
├── parent: ∅
- ├── child:
- │ @ ConstantReadNode (location: (1,2)-(1,5))
- │ └── name: :Foo
- └── delimiter_loc: (1,0)-(1,2) = "::"
+ ├── name: :Foo
+ ├── delimiter_loc: (1,0)-(1,2) = "::"
+ └── name_loc: (1,2)-(1,5) = "Foo"
diff --git a/test/prism/snapshots/whitequark/cpath.txt b/test/prism/snapshots/whitequark/cpath.txt
index b892525646..e801456bf7 100644
--- a/test/prism/snapshots/whitequark/cpath.txt
+++ b/test/prism/snapshots/whitequark/cpath.txt
@@ -9,10 +9,9 @@
│ ├── constant_path:
│ │ @ ConstantPathNode (location: (1,7)-(1,12))
│ │ ├── parent: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (1,9)-(1,12))
- │ │ │ └── name: :Foo
- │ │ └── delimiter_loc: (1,7)-(1,9) = "::"
+ │ │ ├── name: :Foo
+ │ │ ├── delimiter_loc: (1,7)-(1,9) = "::"
+ │ │ └── name_loc: (1,9)-(1,12) = "Foo"
│ ├── body: ∅
│ ├── end_keyword_loc: (1,14)-(1,17) = "end"
│ └── name: :Foo
@@ -24,10 +23,9 @@
│ ├── parent:
│ │ @ ConstantReadNode (location: (3,7)-(3,10))
│ │ └── name: :Bar
- │ ├── child:
- │ │ @ ConstantReadNode (location: (3,12)-(3,15))
- │ │ └── name: :Foo
- │ └── delimiter_loc: (3,10)-(3,12) = "::"
+ │ ├── name: :Foo
+ │ ├── delimiter_loc: (3,10)-(3,12) = "::"
+ │ └── name_loc: (3,12)-(3,15) = "Foo"
├── body: ∅
├── end_keyword_loc: (3,17)-(3,20) = "end"
└── name: :Foo
diff --git a/test/prism/snapshots/whitequark/dedenting_heredoc.txt b/test/prism/snapshots/whitequark/dedenting_heredoc.txt
index acb79e83d2..67896b2415 100644
--- a/test/prism/snapshots/whitequark/dedenting_heredoc.txt
+++ b/test/prism/snapshots/whitequark/dedenting_heredoc.txt
@@ -15,7 +15,7 @@
│ │ ├── flags: ∅
│ │ └── arguments: (length: 1)
│ │ └── @ InterpolatedStringNode (location: (1,2)-(1,8))
- │ │ ├── flags: ∅
+ │ │ ├── flags: mutable
│ │ ├── opening_loc: (1,2)-(1,8) = "<<~\"E\""
│ │ ├── parts: (length: 3)
│ │ │ ├── @ StringNode (location: (2,0)-(3,0))
@@ -30,7 +30,7 @@
│ │ │ │ │ @ StatementsNode (location: (3,4)-(3,9))
│ │ │ │ │ └── body: (length: 1)
│ │ │ │ │ └── @ StringNode (location: (3,4)-(3,9))
- │ │ │ │ │ ├── flags: ∅
+ │ │ │ │ │ ├── flags: frozen
│ │ │ │ │ ├── opening_loc: (3,4)-(3,5) = "\""
│ │ │ │ │ ├── content_loc: (3,5)-(3,8) = " y"
│ │ │ │ │ ├── closing_loc: (3,8)-(3,9) = "\""
diff --git a/test/prism/snapshots/whitequark/forwarded_argument_with_kwrestarg.txt b/test/prism/snapshots/whitequark/forwarded_argument_with_kwrestarg.txt
index c06818a98b..acaf9c052d 100644
--- a/test/prism/snapshots/whitequark/forwarded_argument_with_kwrestarg.txt
+++ b/test/prism/snapshots/whitequark/forwarded_argument_with_kwrestarg.txt
@@ -36,7 +36,7 @@
│ ├── opening_loc: (1,26)-(1,27) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (1,27)-(1,39))
- │ │ ├── flags: contains_keyword_splat
+ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ └── arguments: (length: 2)
│ │ ├── @ LocalVariableReadNode (location: (1,27)-(1,35))
│ │ │ ├── name: :argument
diff --git a/test/prism/snapshots/whitequark/forwarded_kwrestarg.txt b/test/prism/snapshots/whitequark/forwarded_kwrestarg.txt
index adaf111fd7..b4235fb20a 100644
--- a/test/prism/snapshots/whitequark/forwarded_kwrestarg.txt
+++ b/test/prism/snapshots/whitequark/forwarded_kwrestarg.txt
@@ -33,7 +33,7 @@
│ ├── opening_loc: (1,16)-(1,17) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (1,17)-(1,19))
- │ │ ├── flags: contains_keyword_splat
+ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (1,17)-(1,19))
│ │ ├── flags: ∅
diff --git a/test/prism/snapshots/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt b/test/prism/snapshots/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt
index a03421455c..33779abcc1 100644
--- a/test/prism/snapshots/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt
+++ b/test/prism/snapshots/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt
@@ -33,7 +33,7 @@
│ ├── opening_loc: (1,16)-(1,17) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (1,17)-(1,35))
- │ │ ├── flags: contains_keyword_splat
+ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (1,17)-(1,35))
│ │ ├── flags: ∅
diff --git a/test/prism/snapshots/whitequark/keyword_argument_omission.txt b/test/prism/snapshots/whitequark/keyword_argument_omission.txt
index 62e8fecf4e..446b45b56b 100644
--- a/test/prism/snapshots/whitequark/keyword_argument_omission.txt
+++ b/test/prism/snapshots/whitequark/keyword_argument_omission.txt
@@ -12,7 +12,7 @@
├── opening_loc: (1,3)-(1,4) = "("
├── arguments:
│ @ ArgumentsNode (location: (1,4)-(1,10))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (1,4)-(1,10))
│ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt b/test/prism/snapshots/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt
index 6d0bdfb817..db281e2f0d 100644
--- a/test/prism/snapshots/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt
+++ b/test/prism/snapshots/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt
@@ -39,7 +39,7 @@
│ ├── opening_loc: (1,20)-(1,21) = "("
│ ├── arguments:
│ │ @ ArgumentsNode (location: (1,21)-(1,23))
- │ │ ├── flags: contains_keyword_splat
+ │ │ ├── flags: contains_keywords, contains_keyword_splat
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (1,21)-(1,23))
│ │ ├── flags: ∅
diff --git a/test/prism/snapshots/whitequark/masgn_const.txt b/test/prism/snapshots/whitequark/masgn_const.txt
index 56169deb17..ddfccb0d8b 100644
--- a/test/prism/snapshots/whitequark/masgn_const.txt
+++ b/test/prism/snapshots/whitequark/masgn_const.txt
@@ -7,10 +7,9 @@
│ ├── lefts: (length: 2)
│ │ ├── @ ConstantPathTargetNode (location: (1,0)-(1,3))
│ │ │ ├── parent: ∅
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (1,2)-(1,3))
- │ │ │ │ └── name: :A
- │ │ │ └── delimiter_loc: (1,0)-(1,2) = "::"
+ │ │ │ ├── name: :A
+ │ │ │ ├── delimiter_loc: (1,0)-(1,2) = "::"
+ │ │ │ └── name_loc: (1,2)-(1,3) = "A"
│ │ └── @ LocalVariableTargetNode (location: (1,5)-(1,8))
│ │ ├── name: :foo
│ │ └── depth: 0
@@ -28,10 +27,9 @@
│ ├── @ ConstantPathTargetNode (location: (3,0)-(3,7))
│ │ ├── parent:
│ │ │ @ SelfNode (location: (3,0)-(3,4))
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (3,6)-(3,7))
- │ │ │ └── name: :A
- │ │ └── delimiter_loc: (3,4)-(3,6) = "::"
+ │ │ ├── name: :A
+ │ │ ├── delimiter_loc: (3,4)-(3,6) = "::"
+ │ │ └── name_loc: (3,6)-(3,7) = "A"
│ └── @ LocalVariableTargetNode (location: (3,9)-(3,12))
│ ├── name: :foo
│ └── depth: 0
diff --git a/test/prism/snapshots/whitequark/newline_in_hash_argument.txt b/test/prism/snapshots/whitequark/newline_in_hash_argument.txt
index d5e89d87f9..7ef006645b 100644
--- a/test/prism/snapshots/whitequark/newline_in_hash_argument.txt
+++ b/test/prism/snapshots/whitequark/newline_in_hash_argument.txt
@@ -102,7 +102,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (10,8)-(11,1))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (10,8)-(11,1))
│ │ ├── flags: symbol_keys
@@ -141,7 +141,7 @@
├── opening_loc: ∅
├── arguments:
│ @ ArgumentsNode (location: (13,8)-(14,1))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (13,8)-(14,1))
│ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/whitequark/op_asgn.txt b/test/prism/snapshots/whitequark/op_asgn.txt
index 8f24a35ad0..f726617904 100644
--- a/test/prism/snapshots/whitequark/op_asgn.txt
+++ b/test/prism/snapshots/whitequark/op_asgn.txt
@@ -20,8 +20,8 @@
│ ├── message_loc: (1,4)-(1,5) = "A"
│ ├── read_name: :A
│ ├── write_name: :A=
- │ ├── operator: :+
- │ ├── operator_loc: (1,6)-(1,8) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (1,6)-(1,8) = "+="
│ └── value:
│ @ IntegerNode (location: (1,9)-(1,10))
│ ├── flags: decimal
@@ -43,8 +43,8 @@
│ ├── message_loc: (3,4)-(3,5) = "a"
│ ├── read_name: :a
│ ├── write_name: :a=
- │ ├── operator: :+
- │ ├── operator_loc: (3,6)-(3,8) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (3,6)-(3,8) = "+="
│ └── value:
│ @ IntegerNode (location: (3,9)-(3,10))
│ ├── flags: decimal
@@ -66,8 +66,8 @@
├── message_loc: (5,5)-(5,6) = "a"
├── read_name: :a
├── write_name: :a=
- ├── operator: :+
- ├── operator_loc: (5,7)-(5,9) = "+="
+ ├── binary_operator: :+
+ ├── binary_operator_loc: (5,7)-(5,9) = "+="
└── value:
@ IntegerNode (location: (5,10)-(5,11))
├── flags: decimal
diff --git a/test/prism/snapshots/whitequark/op_asgn_cmd.txt b/test/prism/snapshots/whitequark/op_asgn_cmd.txt
index 109c2fd2ed..d2d86b1bf9 100644
--- a/test/prism/snapshots/whitequark/op_asgn_cmd.txt
+++ b/test/prism/snapshots/whitequark/op_asgn_cmd.txt
@@ -20,8 +20,8 @@
│ ├── message_loc: (1,4)-(1,5) = "A"
│ ├── read_name: :A
│ ├── write_name: :A=
- │ ├── operator: :+
- │ ├── operator_loc: (1,6)-(1,8) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (1,6)-(1,8) = "+="
│ └── value:
│ @ CallNode (location: (1,9)-(1,14))
│ ├── flags: ignore_visibility
@@ -63,8 +63,8 @@
│ ├── message_loc: (3,4)-(3,5) = "a"
│ ├── read_name: :a
│ ├── write_name: :a=
- │ ├── operator: :+
- │ ├── operator_loc: (3,6)-(3,8) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (3,6)-(3,8) = "+="
│ └── value:
│ @ CallNode (location: (3,9)-(3,14))
│ ├── flags: ignore_visibility
@@ -103,11 +103,10 @@
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (5,5)-(5,6))
- │ │ │ └── name: :A
- │ │ └── delimiter_loc: (5,3)-(5,5) = "::"
- │ ├── operator_loc: (5,7)-(5,9) = "+="
+ │ │ ├── name: :A
+ │ │ ├── delimiter_loc: (5,3)-(5,5) = "::"
+ │ │ └── name_loc: (5,5)-(5,6) = "A"
+ │ ├── binary_operator_loc: (5,7)-(5,9) = "+="
│ ├── value:
│ │ @ CallNode (location: (5,10)-(5,15))
│ │ ├── flags: ignore_visibility
@@ -132,7 +131,7 @@
│ │ │ └── block: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
- │ └── operator: :+
+ │ └── binary_operator: :+
└── @ CallOperatorWriteNode (location: (7,0)-(7,15))
├── flags: ∅
├── receiver:
@@ -150,8 +149,8 @@
├── message_loc: (7,5)-(7,6) = "a"
├── read_name: :a
├── write_name: :a=
- ├── operator: :+
- ├── operator_loc: (7,7)-(7,9) = "+="
+ ├── binary_operator: :+
+ ├── binary_operator_loc: (7,7)-(7,9) = "+="
└── value:
@ CallNode (location: (7,10)-(7,15))
├── flags: ignore_visibility
diff --git a/test/prism/snapshots/whitequark/op_asgn_index.txt b/test/prism/snapshots/whitequark/op_asgn_index.txt
index fe077fae13..b302abdafe 100644
--- a/test/prism/snapshots/whitequark/op_asgn_index.txt
+++ b/test/prism/snapshots/whitequark/op_asgn_index.txt
@@ -30,8 +30,8 @@
│ └── value: 1
├── closing_loc: (1,8)-(1,9) = "]"
├── block: ∅
- ├── operator: :+
- ├── operator_loc: (1,10)-(1,12) = "+="
+ ├── binary_operator: :+
+ ├── binary_operator_loc: (1,10)-(1,12) = "+="
└── value:
@ IntegerNode (location: (1,13)-(1,14))
├── flags: decimal
diff --git a/test/prism/snapshots/whitequark/op_asgn_index_cmd.txt b/test/prism/snapshots/whitequark/op_asgn_index_cmd.txt
index 87082aad94..319ed1a51a 100644
--- a/test/prism/snapshots/whitequark/op_asgn_index_cmd.txt
+++ b/test/prism/snapshots/whitequark/op_asgn_index_cmd.txt
@@ -30,8 +30,8 @@
│ └── value: 1
├── closing_loc: (1,8)-(1,9) = "]"
├── block: ∅
- ├── operator: :+
- ├── operator_loc: (1,10)-(1,12) = "+="
+ ├── binary_operator: :+
+ ├── binary_operator_loc: (1,10)-(1,12) = "+="
└── value:
@ CallNode (location: (1,13)-(1,18))
├── flags: ignore_visibility
diff --git a/test/prism/snapshots/whitequark/parser_bug_525.txt b/test/prism/snapshots/whitequark/parser_bug_525.txt
index a69b8a207f..3a31a97cdc 100644
--- a/test/prism/snapshots/whitequark/parser_bug_525.txt
+++ b/test/prism/snapshots/whitequark/parser_bug_525.txt
@@ -12,7 +12,7 @@
├── opening_loc: ∅
├── arguments:
│ @ ArgumentsNode (location: (1,3)-(1,11))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 1)
│ └── @ KeywordHashNode (location: (1,3)-(1,11))
│ ├── flags: symbol_keys
diff --git a/test/prism/snapshots/whitequark/rescue_mod_op_assign.txt b/test/prism/snapshots/whitequark/rescue_mod_op_assign.txt
index b269104f30..840e5a4fc0 100644
--- a/test/prism/snapshots/whitequark/rescue_mod_op_assign.txt
+++ b/test/prism/snapshots/whitequark/rescue_mod_op_assign.txt
@@ -5,7 +5,7 @@
└── body: (length: 1)
└── @ LocalVariableOperatorWriteNode (location: (1,0)-(1,22))
├── name_loc: (1,0)-(1,3) = "foo"
- ├── operator_loc: (1,4)-(1,6) = "+="
+ ├── binary_operator_loc: (1,4)-(1,6) = "+="
├── value:
│ @ RescueModifierNode (location: (1,7)-(1,22))
│ ├── expression:
@@ -32,5 +32,5 @@
│ ├── closing_loc: ∅
│ └── block: ∅
├── name: :foo
- ├── operator: :+
+ ├── binary_operator: :+
└── depth: 0
diff --git a/test/prism/snapshots/whitequark/return.txt b/test/prism/snapshots/whitequark/return.txt
index ddfbae85c8..5c98259103 100644
--- a/test/prism/snapshots/whitequark/return.txt
+++ b/test/prism/snapshots/whitequark/return.txt
@@ -4,9 +4,11 @@
@ StatementsNode (location: (1,0)-(7,11))
└── body: (length: 4)
├── @ ReturnNode (location: (1,0)-(1,6))
+ │ ├── flags: ∅
│ ├── keyword_loc: (1,0)-(1,6) = "return"
│ └── arguments: ∅
├── @ ReturnNode (location: (3,0)-(3,10))
+ │ ├── flags: ∅
│ ├── keyword_loc: (3,0)-(3,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (3,7)-(3,10))
@@ -23,6 +25,7 @@
│ ├── closing_loc: ∅
│ └── block: ∅
├── @ ReturnNode (location: (5,0)-(5,8))
+ │ ├── flags: ∅
│ ├── keyword_loc: (5,0)-(5,6) = "return"
│ └── arguments:
│ @ ArgumentsNode (location: (5,6)-(5,8))
@@ -33,6 +36,7 @@
│ ├── opening_loc: (5,6)-(5,7) = "("
│ └── closing_loc: (5,7)-(5,8) = ")"
└── @ ReturnNode (location: (7,0)-(7,11))
+ ├── flags: ∅
├── keyword_loc: (7,0)-(7,6) = "return"
└── arguments:
@ ArgumentsNode (location: (7,6)-(7,11))
diff --git a/test/prism/snapshots/whitequark/return_block.txt b/test/prism/snapshots/whitequark/return_block.txt
index 5b8141e4f3..36746a361b 100644
--- a/test/prism/snapshots/whitequark/return_block.txt
+++ b/test/prism/snapshots/whitequark/return_block.txt
@@ -4,6 +4,7 @@
@ StatementsNode (location: (1,0)-(1,21))
└── body: (length: 1)
└── @ ReturnNode (location: (1,0)-(1,21))
+ ├── flags: ∅
├── keyword_loc: (1,0)-(1,6) = "return"
└── arguments:
@ ArgumentsNode (location: (1,7)-(1,21))
diff --git a/test/prism/snapshots/whitequark/ruby_bug_11380.txt b/test/prism/snapshots/whitequark/ruby_bug_11380.txt
index b7a7ef9a98..d5ec10b06c 100644
--- a/test/prism/snapshots/whitequark/ruby_bug_11380.txt
+++ b/test/prism/snapshots/whitequark/ruby_bug_11380.txt
@@ -12,7 +12,7 @@
├── opening_loc: ∅
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(1,21))
- │ ├── flags: ∅
+ │ ├── flags: contains_keywords
│ └── arguments: (length: 2)
│ ├── @ LambdaNode (location: (1,2)-(1,15))
│ │ ├── locals: []
diff --git a/test/prism/snapshots/whitequark/ruby_bug_12073.txt b/test/prism/snapshots/whitequark/ruby_bug_12073.txt
index 9db30f6fec..2b4d3eab2a 100644
--- a/test/prism/snapshots/whitequark/ruby_bug_12073.txt
+++ b/test/prism/snapshots/whitequark/ruby_bug_12073.txt
@@ -21,7 +21,7 @@
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (1,9)-(1,13))
- │ │ ├── flags: ∅
+ │ │ ├── flags: contains_keywords
│ │ └── arguments: (length: 1)
│ │ └── @ KeywordHashNode (location: (1,9)-(1,13))
│ │ ├── flags: symbol_keys
@@ -75,10 +75,9 @@
│ │ │ ├── parent:
│ │ │ │ @ ConstantReadNode (location: (3,21)-(3,22))
│ │ │ │ └── name: :A
- │ │ │ ├── child:
- │ │ │ │ @ ConstantReadNode (location: (3,24)-(3,25))
- │ │ │ │ └── name: :B
- │ │ │ └── delimiter_loc: (3,22)-(3,24) = "::"
+ │ │ │ ├── name: :B
+ │ │ │ ├── delimiter_loc: (3,22)-(3,24) = "::"
+ │ │ │ └── name_loc: (3,24)-(3,25) = "B"
│ │ └── @ StringNode (location: (3,27)-(3,29))
│ │ ├── flags: ∅
│ │ ├── opening_loc: (3,27)-(3,28) = "'"
diff --git a/test/prism/snapshots/whitequark/ruby_bug_12402.txt b/test/prism/snapshots/whitequark/ruby_bug_12402.txt
index df5aea00c3..4935007f8a 100644
--- a/test/prism/snapshots/whitequark/ruby_bug_12402.txt
+++ b/test/prism/snapshots/whitequark/ruby_bug_12402.txt
@@ -5,7 +5,7 @@
└── body: (length: 14)
├── @ LocalVariableOperatorWriteNode (location: (1,0)-(1,27))
│ ├── name_loc: (1,0)-(1,3) = "foo"
- │ ├── operator_loc: (1,4)-(1,6) = "+="
+ │ ├── binary_operator_loc: (1,4)-(1,6) = "+="
│ ├── value:
│ │ @ RescueModifierNode (location: (1,7)-(1,27))
│ │ ├── expression:
@@ -36,11 +36,11 @@
│ │ └── rescue_expression:
│ │ @ NilNode (location: (1,24)-(1,27))
│ ├── name: :foo
- │ ├── operator: :+
+ │ ├── binary_operator: :+
│ └── depth: 0
├── @ LocalVariableOperatorWriteNode (location: (3,0)-(3,28))
│ ├── name_loc: (3,0)-(3,3) = "foo"
- │ ├── operator_loc: (3,4)-(3,6) = "+="
+ │ ├── binary_operator_loc: (3,4)-(3,6) = "+="
│ ├── value:
│ │ @ RescueModifierNode (location: (3,7)-(3,28))
│ │ ├── expression:
@@ -71,7 +71,7 @@
│ │ └── rescue_expression:
│ │ @ NilNode (location: (3,25)-(3,28))
│ ├── name: :foo
- │ ├── operator: :+
+ │ ├── binary_operator: :+
│ └── depth: 0
├── @ LocalVariableWriteNode (location: (5,0)-(5,26))
│ ├── name: :foo
@@ -151,8 +151,8 @@
│ ├── message_loc: (9,4)-(9,5) = "C"
│ ├── read_name: :C
│ ├── write_name: :C=
- │ ├── operator: :+
- │ ├── operator_loc: (9,6)-(9,8) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (9,6)-(9,8) = "+="
│ └── value:
│ @ RescueModifierNode (location: (9,9)-(9,29))
│ ├── expression:
@@ -192,8 +192,8 @@
│ ├── message_loc: (11,4)-(11,5) = "C"
│ ├── read_name: :C
│ ├── write_name: :C=
- │ ├── operator: :+
- │ ├── operator_loc: (11,6)-(11,8) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (11,6)-(11,8) = "+="
│ └── value:
│ @ RescueModifierNode (location: (11,9)-(11,30))
│ ├── expression:
@@ -233,8 +233,8 @@
│ ├── message_loc: (13,4)-(13,5) = "m"
│ ├── read_name: :m
│ ├── write_name: :m=
- │ ├── operator: :+
- │ ├── operator_loc: (13,6)-(13,8) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (13,6)-(13,8) = "+="
│ └── value:
│ @ RescueModifierNode (location: (13,9)-(13,29))
│ ├── expression:
@@ -274,8 +274,8 @@
│ ├── message_loc: (15,4)-(15,5) = "m"
│ ├── read_name: :m
│ ├── write_name: :m=
- │ ├── operator: :+
- │ ├── operator_loc: (15,6)-(15,8) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (15,6)-(15,8) = "+="
│ └── value:
│ @ RescueModifierNode (location: (15,9)-(15,30))
│ ├── expression:
@@ -312,10 +312,9 @@
│ │ │ @ LocalVariableReadNode (location: (17,0)-(17,3))
│ │ │ ├── name: :foo
│ │ │ └── depth: 0
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (17,5)-(17,6))
- │ │ │ └── name: :C
- │ │ └── delimiter_loc: (17,3)-(17,5) = "::"
+ │ │ ├── name: :C
+ │ │ ├── delimiter_loc: (17,3)-(17,5) = "::"
+ │ │ └── name_loc: (17,5)-(17,6) = "C"
│ ├── operator_loc: (17,7)-(17,10) = "||="
│ └── value:
│ @ RescueModifierNode (location: (17,11)-(17,31))
@@ -353,10 +352,9 @@
│ │ │ @ LocalVariableReadNode (location: (19,0)-(19,3))
│ │ │ ├── name: :foo
│ │ │ └── depth: 0
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (19,5)-(19,6))
- │ │ │ └── name: :C
- │ │ └── delimiter_loc: (19,3)-(19,5) = "::"
+ │ │ ├── name: :C
+ │ │ ├── delimiter_loc: (19,3)-(19,5) = "::"
+ │ │ └── name_loc: (19,5)-(19,6) = "C"
│ ├── operator_loc: (19,7)-(19,10) = "||="
│ └── value:
│ @ RescueModifierNode (location: (19,11)-(19,32))
@@ -397,8 +395,8 @@
│ ├── message_loc: (21,5)-(21,6) = "m"
│ ├── read_name: :m
│ ├── write_name: :m=
- │ ├── operator: :+
- │ ├── operator_loc: (21,7)-(21,9) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (21,7)-(21,9) = "+="
│ └── value:
│ @ RescueModifierNode (location: (21,10)-(21,30))
│ ├── expression:
@@ -438,8 +436,8 @@
│ ├── message_loc: (23,5)-(23,6) = "m"
│ ├── read_name: :m
│ ├── write_name: :m=
- │ ├── operator: :+
- │ ├── operator_loc: (23,7)-(23,9) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (23,7)-(23,9) = "+="
│ └── value:
│ @ RescueModifierNode (location: (23,10)-(23,31))
│ ├── expression:
@@ -486,8 +484,8 @@
│ │ └── value: 0
│ ├── closing_loc: (25,5)-(25,6) = "]"
│ ├── block: ∅
- │ ├── operator: :+
- │ ├── operator_loc: (25,7)-(25,9) = "+="
+ │ ├── binary_operator: :+
+ │ ├── binary_operator_loc: (25,7)-(25,9) = "+="
│ └── value:
│ @ RescueModifierNode (location: (25,10)-(25,30))
│ ├── expression:
@@ -534,8 +532,8 @@
│ └── value: 0
├── closing_loc: (27,5)-(27,6) = "]"
├── block: ∅
- ├── operator: :+
- ├── operator_loc: (27,7)-(27,9) = "+="
+ ├── binary_operator: :+
+ ├── binary_operator_loc: (27,7)-(27,9) = "+="
└── value:
@ RescueModifierNode (location: (27,10)-(27,31))
├── expression:
diff --git a/test/prism/snapshots/whitequark/ruby_bug_12669.txt b/test/prism/snapshots/whitequark/ruby_bug_12669.txt
index 86b021351b..6151143ba8 100644
--- a/test/prism/snapshots/whitequark/ruby_bug_12669.txt
+++ b/test/prism/snapshots/whitequark/ruby_bug_12669.txt
@@ -5,11 +5,11 @@
└── body: (length: 4)
├── @ LocalVariableOperatorWriteNode (location: (1,0)-(1,18))
│ ├── name_loc: (1,0)-(1,1) = "a"
- │ ├── operator_loc: (1,2)-(1,4) = "+="
+ │ ├── binary_operator_loc: (1,2)-(1,4) = "+="
│ ├── value:
│ │ @ LocalVariableOperatorWriteNode (location: (1,5)-(1,18))
│ │ ├── name_loc: (1,5)-(1,6) = "b"
- │ │ ├── operator_loc: (1,7)-(1,9) = "+="
+ │ │ ├── binary_operator_loc: (1,7)-(1,9) = "+="
│ │ ├── value:
│ │ │ @ CallNode (location: (1,10)-(1,18))
│ │ │ ├── flags: ignore_visibility
@@ -31,14 +31,14 @@
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ ├── name: :b
- │ │ ├── operator: :+
+ │ │ ├── binary_operator: :+
│ │ └── depth: 0
│ ├── name: :a
- │ ├── operator: :+
+ │ ├── binary_operator: :+
│ └── depth: 0
├── @ LocalVariableOperatorWriteNode (location: (3,0)-(3,17))
│ ├── name_loc: (3,0)-(3,1) = "a"
- │ ├── operator_loc: (3,2)-(3,4) = "+="
+ │ ├── binary_operator_loc: (3,2)-(3,4) = "+="
│ ├── value:
│ │ @ LocalVariableWriteNode (location: (3,5)-(3,17))
│ │ ├── name: :b
@@ -66,7 +66,7 @@
│ │ │ └── block: ∅
│ │ └── operator_loc: (3,7)-(3,8) = "="
│ ├── name: :a
- │ ├── operator: :+
+ │ ├── binary_operator: :+
│ └── depth: 0
├── @ LocalVariableWriteNode (location: (5,0)-(5,17))
│ ├── name: :a
@@ -75,7 +75,7 @@
│ ├── value:
│ │ @ LocalVariableOperatorWriteNode (location: (5,4)-(5,17))
│ │ ├── name_loc: (5,4)-(5,5) = "b"
- │ │ ├── operator_loc: (5,6)-(5,8) = "+="
+ │ │ ├── binary_operator_loc: (5,6)-(5,8) = "+="
│ │ ├── value:
│ │ │ @ CallNode (location: (5,9)-(5,17))
│ │ │ ├── flags: ignore_visibility
@@ -97,7 +97,7 @@
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ ├── name: :b
- │ │ ├── operator: :+
+ │ │ ├── binary_operator: :+
│ │ └── depth: 0
│ └── operator_loc: (5,2)-(5,3) = "="
└── @ LocalVariableWriteNode (location: (7,0)-(7,16))
diff --git a/test/prism/snapshots/whitequark/ruby_bug_9669.txt b/test/prism/snapshots/whitequark/ruby_bug_9669.txt
index a73000bed0..910b08c3ef 100644
--- a/test/prism/snapshots/whitequark/ruby_bug_9669.txt
+++ b/test/prism/snapshots/whitequark/ruby_bug_9669.txt
@@ -24,6 +24,7 @@
│ │ @ StatementsNode (location: (2,0)-(2,6))
│ │ └── body: (length: 1)
│ │ └── @ ReturnNode (location: (2,0)-(2,6))
+ │ │ ├── flags: redundant
│ │ ├── keyword_loc: (2,0)-(2,6) = "return"
│ │ └── arguments: ∅
│ ├── locals: [:b]
diff --git a/test/prism/snapshots/whitequark/send_attr_asgn.txt b/test/prism/snapshots/whitequark/send_attr_asgn.txt
index 392ae5587e..1d09daa4a6 100644
--- a/test/prism/snapshots/whitequark/send_attr_asgn.txt
+++ b/test/prism/snapshots/whitequark/send_attr_asgn.txt
@@ -69,10 +69,9 @@
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
- │ │ ├── child:
- │ │ │ @ ConstantReadNode (location: (5,5)-(5,6))
- │ │ │ └── name: :A
- │ │ └── delimiter_loc: (5,3)-(5,5) = "::"
+ │ │ ├── name: :A
+ │ │ ├── delimiter_loc: (5,3)-(5,5) = "::"
+ │ │ └── name_loc: (5,5)-(5,6) = "A"
│ ├── operator_loc: (5,7)-(5,8) = "="
│ └── value:
│ @ IntegerNode (location: (5,9)-(5,10))
diff --git a/test/prism/snapshots/whitequark/var_op_asgn.txt b/test/prism/snapshots/whitequark/var_op_asgn.txt
index f423a62dee..f20f612fa2 100644
--- a/test/prism/snapshots/whitequark/var_op_asgn.txt
+++ b/test/prism/snapshots/whitequark/var_op_asgn.txt
@@ -6,30 +6,30 @@
├── @ ClassVariableOperatorWriteNode (location: (1,0)-(1,11))
│ ├── name: :@@var
│ ├── name_loc: (1,0)-(1,5) = "@@var"
- │ ├── operator_loc: (1,6)-(1,8) = "|="
+ │ ├── binary_operator_loc: (1,6)-(1,8) = "|="
│ ├── value:
│ │ @ IntegerNode (location: (1,9)-(1,11))
│ │ ├── flags: decimal
│ │ └── value: 10
- │ └── operator: :|
+ │ └── binary_operator: :|
├── @ InstanceVariableOperatorWriteNode (location: (3,0)-(3,7))
│ ├── name: :@a
│ ├── name_loc: (3,0)-(3,2) = "@a"
- │ ├── operator_loc: (3,3)-(3,5) = "|="
+ │ ├── binary_operator_loc: (3,3)-(3,5) = "|="
│ ├── value:
│ │ @ IntegerNode (location: (3,6)-(3,7))
│ │ ├── flags: decimal
│ │ └── value: 1
- │ └── operator: :|
+ │ └── binary_operator: :|
├── @ LocalVariableOperatorWriteNode (location: (5,0)-(5,6))
│ ├── name_loc: (5,0)-(5,1) = "a"
- │ ├── operator_loc: (5,2)-(5,4) = "+="
+ │ ├── binary_operator_loc: (5,2)-(5,4) = "+="
│ ├── value:
│ │ @ IntegerNode (location: (5,5)-(5,6))
│ │ ├── flags: decimal
│ │ └── value: 1
│ ├── name: :a
- │ ├── operator: :+
+ │ ├── binary_operator: :+
│ └── depth: 0
└── @ DefNode (location: (7,0)-(7,23))
├── name: :a
@@ -42,12 +42,12 @@
│ └── @ ClassVariableOperatorWriteNode (location: (7,7)-(7,18))
│ ├── name: :@@var
│ ├── name_loc: (7,7)-(7,12) = "@@var"
- │ ├── operator_loc: (7,13)-(7,15) = "|="
+ │ ├── binary_operator_loc: (7,13)-(7,15) = "|="
│ ├── value:
│ │ @ IntegerNode (location: (7,16)-(7,18))
│ │ ├── flags: decimal
│ │ └── value: 10
- │ └── operator: :|
+ │ └── binary_operator: :|
├── locals: []
├── def_keyword_loc: (7,0)-(7,3) = "def"
├── operator_loc: ∅
diff --git a/test/prism/snapshots/whitequark/var_op_asgn_cmd.txt b/test/prism/snapshots/whitequark/var_op_asgn_cmd.txt
index d56c099c7e..0bfa06d5b7 100644
--- a/test/prism/snapshots/whitequark/var_op_asgn_cmd.txt
+++ b/test/prism/snapshots/whitequark/var_op_asgn_cmd.txt
@@ -5,7 +5,7 @@
└── body: (length: 1)
└── @ LocalVariableOperatorWriteNode (location: (1,0)-(1,12))
├── name_loc: (1,0)-(1,3) = "foo"
- ├── operator_loc: (1,4)-(1,6) = "+="
+ ├── binary_operator_loc: (1,4)-(1,6) = "+="
├── value:
│ @ CallNode (location: (1,7)-(1,12))
│ ├── flags: ignore_visibility
@@ -24,5 +24,5 @@
│ ├── closing_loc: ∅
│ └── block: ∅
├── name: :foo
- ├── operator: :+
+ ├── binary_operator: :+
└── depth: 0
diff --git a/test/prism/unescape_test.rb b/test/prism/unescape_test.rb
index 2a352c5234..3f78a59b11 100644
--- a/test/prism/unescape_test.rb
+++ b/test/prism/unescape_test.rb
@@ -38,7 +38,7 @@ module Prism
end
def prism(escape)
- result = Prism.parse(code(escape))
+ result = Prism.parse(code(escape), encoding: "binary")
if result.success?
yield result.value.statements.body.first
diff --git a/test/prism/warnings_test.rb b/test/prism/warnings_test.rb
index 7eb1bbd2e1..b138a3cb43 100644
--- a/test/prism/warnings_test.rb
+++ b/test/prism/warnings_test.rb
@@ -44,6 +44,7 @@ module Prism
def test_duplicated_hash_key
assert_warning("{ a: 1, a: 2 }", "duplicated and overwritten")
+ assert_warning("{ a: 1, **{ a: 2 } }", "duplicated and overwritten")
end
def test_duplicated_when_clause
@@ -63,6 +64,15 @@ module Prism
assert_warning("if true\nelsif\nfalse; end", "end of line")
end
+ def test_shareable_constant_value
+ assert_warning("foo # shareable_constant_value: none", "ignored")
+ assert_warning("\v # shareable_constant_value: none", "ignored")
+
+ refute_warning("# shareable_constant_value: none")
+ refute_warning(" # shareable_constant_value: none")
+ refute_warning("\t\t# shareable_constant_value: none")
+ end
+
def test_string_in_predicate
assert_warning("if 'foo'; end", "string")
assert_warning("if \"\#{foo}\"; end", "string")
diff --git a/test/reline/test_config.rb b/test/reline/test_config.rb
index 9ead047ce4..6068292847 100644
--- a/test/reline/test_config.rb
+++ b/test/reline/test_config.rb
@@ -216,6 +216,38 @@ class Reline::Config::Test < Reline::TestCase
end
end
+ def test_nested_if_else
+ @config.read_lines(<<~LINES.lines)
+ $if Ruby
+ "\x1": "O"
+ $if NotRuby
+ "\x2": "X"
+ $else
+ "\x3": "O"
+ $if Ruby
+ "\x4": "O"
+ $else
+ "\x5": "X"
+ $endif
+ "\x6": "O"
+ $endif
+ "\x7": "O"
+ $else
+ "\x8": "X"
+ $if NotRuby
+ "\x9": "X"
+ $else
+ "\xA": "X"
+ $endif
+ "\xB": "X"
+ $endif
+ "\xC": "O"
+ LINES
+ keys = [0x1, 0x3, 0x4, 0x6, 0x7, 0xC]
+ key_bindings = keys.to_h { |k| [[k.ord], ['O'.ord]] }
+ assert_equal(key_bindings, @config.instance_variable_get(:@additional_key_bindings)[:emacs])
+ end
+
def test_unclosed_if
e = assert_raise(Reline::Config::InvalidInputrc) do
@config.read_lines(<<~LINES.lines, "INPUTRC")
@@ -243,6 +275,78 @@ class Reline::Config::Test < Reline::TestCase
assert_equal "INPUTRC:1: unmatched endif", e.message
end
+ def test_if_with_mode
+ @config.read_lines(<<~LINES.lines)
+ $if mode=emacs
+ "\C-e": history-search-backward # comment
+ $else
+ "\C-f": history-search-forward
+ $endif
+ LINES
+
+ assert_equal({[5] => :history_search_backward}, @config.instance_variable_get(:@additional_key_bindings)[:emacs])
+ assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_insert])
+ assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_command])
+ end
+
+ def test_else
+ @config.read_lines(<<~LINES.lines)
+ $if mode=vi
+ "\C-e": history-search-backward # comment
+ $else
+ "\C-f": history-search-forward
+ $endif
+ LINES
+
+ assert_equal({[6] => :history_search_forward}, @config.instance_variable_get(:@additional_key_bindings)[:emacs])
+ assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_insert])
+ assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_command])
+ end
+
+ def test_if_with_invalid_mode
+ @config.read_lines(<<~LINES.lines)
+ $if mode=vim
+ "\C-e": history-search-backward
+ $else
+ "\C-f": history-search-forward # comment
+ $endif
+ LINES
+
+ assert_equal({[6] => :history_search_forward}, @config.instance_variable_get(:@additional_key_bindings)[:emacs])
+ assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_insert])
+ assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_command])
+ end
+
+ def test_mode_label_differs_from_keymap_label
+ @config.read_lines(<<~LINES.lines)
+ # Sets mode_label and keymap_label to vi
+ set editing-mode vi
+ # Change keymap_label to emacs. mode_label is still vi.
+ set keymap emacs
+ # condition=true because current mode_label is vi
+ $if mode=vi
+ # sets keybinding to current keymap_label=emacs
+ "\C-e": history-search-backward
+ $endif
+ LINES
+ assert_equal({[5] => :history_search_backward}, @config.instance_variable_get(:@additional_key_bindings)[:emacs])
+ assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_insert])
+ assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_command])
+ end
+
+ def test_if_without_else_condition
+ @config.read_lines(<<~LINES.lines)
+ set editing-mode vi
+ $if mode=vi
+ "\C-e": history-search-backward
+ $endif
+ LINES
+
+ assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:emacs])
+ assert_equal({[5] => :history_search_backward}, @config.instance_variable_get(:@additional_key_bindings)[:vi_insert])
+ assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_command])
+ end
+
def test_default_key_bindings
@config.add_default_key_binding('abcd'.bytes, 'EFGH'.bytes)
@config.read_lines(<<~'LINES'.lines)
@@ -313,6 +417,18 @@ class Reline::Config::Test < Reline::TestCase
assert_equal expected, @config.key_bindings
end
+ def test_key_bindings_with_reset
+ # @config.reset is called after each readline.
+ # inputrc file is read once, so key binding shouldn't be cleared by @config.reset
+ @config.add_default_key_binding('default'.bytes, 'DEFAULT'.bytes)
+ @config.read_lines(<<~'LINES'.lines)
+ "additional": "ADDITIONAL"
+ LINES
+ @config.reset
+ expected = { 'default'.bytes => 'DEFAULT'.bytes, 'additional'.bytes => 'ADDITIONAL'.bytes }
+ assert_equal expected, @config.key_bindings
+ end
+
def test_history_size
@config.read_lines(<<~LINES.lines)
set history-size 5000
diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb
index a9baf9ad37..013ca2f7b3 100644
--- a/test/reline/test_key_actor_emacs.rb
+++ b/test/reline/test_key_actor_emacs.rb
@@ -787,9 +787,22 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
input_keys('b')
input_keys("\C-i", false)
assert_line_around_cursor('foo_ba', '')
+ input_keys("\C-h")
+ input_key_by_symbol(:complete)
+ assert_line_around_cursor('foo_ba', '')
+ input_keys("\C-h", false)
+ input_key_by_symbol(:menu_complete)
+ assert_line_around_cursor('foo_bar', '')
+ input_key_by_symbol(:menu_complete)
+ assert_line_around_cursor('foo_baz', '')
+ input_keys("\C-h", false)
+ input_key_by_symbol(:menu_complete_backward)
+ assert_line_around_cursor('foo_baz', '')
+ input_key_by_symbol(:menu_complete_backward)
+ assert_line_around_cursor('foo_bar', '')
end
- def test_autocompletion_with_upward_navigation
+ def test_autocompletion
@config.autocompletion = true
@line_editor.completion_proc = proc { |word|
%w{
@@ -806,31 +819,14 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
assert_line_around_cursor('Readline', '')
input_keys("\C-i", false)
assert_line_around_cursor('Regexp', '')
- @line_editor.input_key(Reline::Key.new(:completion_journey_up, :completion_journey_up, false))
+ input_key_by_symbol(:completion_journey_up)
assert_line_around_cursor('Readline', '')
- ensure
- @config.autocompletion = false
- end
-
- def test_autocompletion_with_upward_navigation_and_menu_complete_backward
- @config.autocompletion = true
- @line_editor.completion_proc = proc { |word|
- %w{
- Readline
- Regexp
- RegexpError
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('Re')
- assert_line_around_cursor('Re', '')
- input_keys("\C-i", false)
- assert_line_around_cursor('Readline', '')
- input_keys("\C-i", false)
+ input_key_by_symbol(:complete)
assert_line_around_cursor('Regexp', '')
- @line_editor.input_key(Reline::Key.new(:menu_complete_backward, :menu_complete_backward, false))
+ input_key_by_symbol(:menu_complete_backward)
assert_line_around_cursor('Readline', '')
+ input_key_by_symbol(:menu_complete)
+ assert_line_around_cursor('Regexp', '')
ensure
@config.autocompletion = false
end
@@ -1441,4 +1437,72 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
@line_editor.__send__(:vi_editing_mode, nil)
assert(@config.editing_mode_is?(:vi_insert))
end
+
+ def test_undo
+ input_keys("\C-_", false)
+ assert_line_around_cursor('', '')
+ input_keys("aあb\C-h\C-h\C-h", false)
+ assert_line_around_cursor('', '')
+ input_keys("\C-_", false)
+ assert_line_around_cursor('a', '')
+ input_keys("\C-_", false)
+ assert_line_around_cursor('aあ', '')
+ input_keys("\C-_", false)
+ assert_line_around_cursor('aあb', '')
+ input_keys("\C-_", false)
+ assert_line_around_cursor('aあ', '')
+ input_keys("\C-_", false)
+ assert_line_around_cursor('a', '')
+ input_keys("\C-_", false)
+ assert_line_around_cursor('', '')
+ end
+
+ def test_undo_with_cursor_position
+ input_keys("abc\C-b\C-h", false)
+ assert_line_around_cursor('a', 'c')
+ input_keys("\C-_", false)
+ assert_line_around_cursor('ab', 'c')
+ input_keys("あいう\C-b\C-h", false)
+ assert_line_around_cursor('abあ', 'うc')
+ input_keys("\C-_", false)
+ assert_line_around_cursor('abあい', 'うc')
+ end
+
+ def test_undo_with_multiline
+ @line_editor.multiline_on
+ @line_editor.confirm_multiline_termination_proc = proc {}
+ input_keys("1\n2\n3", false)
+ assert_whole_lines(["1", "2", "3"])
+ assert_line_index(2)
+ assert_line_around_cursor('3', '')
+ input_keys("\C-p\C-h\C-h", false)
+ assert_whole_lines(["1", "3"])
+ assert_line_index(0)
+ assert_line_around_cursor('1', '')
+ input_keys("\C-_", false)
+ assert_whole_lines(["1", "", "3"])
+ assert_line_index(1)
+ assert_line_around_cursor('', '')
+ input_keys("\C-_", false)
+ assert_whole_lines(["1", "2", "3"])
+ assert_line_index(1)
+ assert_line_around_cursor('2', '')
+ input_keys("\C-_", false)
+ assert_whole_lines(["1", "2", ""])
+ assert_line_index(2)
+ assert_line_around_cursor('', '')
+ input_keys("\C-_", false)
+ assert_whole_lines(["1", "2"])
+ assert_line_index(1)
+ assert_line_around_cursor('2', '')
+ end
+
+ def test_undo_with_many_times
+ str = "a" + "b" * 100
+ input_keys(str, false)
+ 100.times { input_keys("\C-_", false) }
+ assert_line_around_cursor('a', '')
+ input_keys("\C-_", false)
+ assert_line_around_cursor('a', '')
+ end
end
diff --git a/test/reline/test_line_editor.rb b/test/reline/test_line_editor.rb
index bf688ac3c6..7a38ecd596 100644
--- a/test/reline/test_line_editor.rb
+++ b/test/reline/test_line_editor.rb
@@ -112,6 +112,36 @@ class Reline::LineEditor
end
end
+ def test_multibyte
+ base = [0, 12, '一二三一二三']
+ left = [0, 3, 'LLL']
+ right = [9, 3, 'RRR']
+ front = [3, 6, 'FFFFFF']
+ # 一 FFFFFF 三
+ # 一二三一二三
+ assert_output '[COL_2]二三一二' do
+ @line_editor.render_line_differential([base, front], [base, nil])
+ end
+
+ # LLLFFFFFF 三
+ # LLL 三一二三
+ assert_output '[COL_3] 三一二' do
+ @line_editor.render_line_differential([base, left, front], [base, left, nil])
+ end
+
+ # 一 FFFFFFRRR
+ # 一二三一 RRR
+ assert_output '[COL_2]二三一 ' do
+ @line_editor.render_line_differential([base, right, front], [base, right, nil])
+ end
+
+ # LLLFFFFFFRRR
+ # LLL 三一 RRR
+ assert_output '[COL_3] 三一 ' do
+ @line_editor.render_line_differential([base, left, right, front], [base, left, right, nil])
+ end
+ end
+
def test_complicated
state_a = [nil, [19, 7, 'bbbbbbb'], [15, 8, 'cccccccc'], [10, 5, 'ddddd'], [18, 4, 'eeee'], [1, 3, 'fff'], [17, 2, 'gg'], [7, 1, 'h']]
state_b = [[5, 9, 'aaaaaaaaa'], nil, [15, 8, 'cccccccc'], nil, [18, 4, 'EEEE'], [25, 4, 'ffff'], [17, 2, 'gg'], [2, 2, 'hh']]
diff --git a/test/reline/test_reline.rb b/test/reline/test_reline.rb
index 40c880c11f..a20a5c9f44 100644
--- a/test/reline/test_reline.rb
+++ b/test/reline/test_reline.rb
@@ -378,10 +378,28 @@ class Reline::Test < Reline::TestCase
assert_equal("Reline::GeneralIO", out.chomp)
end
+ def test_require_reline_should_not_trigger_winsize
+ pend if win?
+ lib = File.expand_path("../../lib", __dir__)
+ code = <<~RUBY
+ require "io/console"
+ def STDIN.tty?; true; end
+ def STDOUT.tty?; true; end
+ def STDIN.winsize; raise; end
+ require("reline") && p(Reline.core.io_gate)
+ RUBY
+ out = IO.popen([{}, Reline.test_rubybin, "-I#{lib}", "-e", code], &:read)
+ assert_equal("Reline::ANSI", out.chomp)
+ end
+
+ def win?
+ /mswin|mingw/.match?(RUBY_PLATFORM)
+ end
+
def get_reline_encoding
if encoding = Reline.core.encoding
encoding
- elsif RUBY_PLATFORM =~ /mswin|mingw/
+ elsif win?
Encoding::UTF_8
else
Encoding::default_external
diff --git a/test/reline/test_unicode.rb b/test/reline/test_unicode.rb
index 834f7114c4..deba4d4681 100644
--- a/test/reline/test_unicode.rb
+++ b/test/reline/test_unicode.rb
@@ -38,11 +38,16 @@ class Reline::Unicode::Test < Reline::TestCase
assert_equal [["ab\e]0;1\ac", nil, "\e]0;1\ad"], 2], Reline::Unicode.split_by_width("ab\e]0;1\acd", 3)
end
+ def test_split_by_width_csi_reset_sgr_optimization
+ assert_equal [["\e[1ma\e[mb\e[2mc", nil, "\e[2md\e[0me\e[3mf", nil, "\e[3mg"], 3], Reline::Unicode.split_by_width("\e[1ma\e[mb\e[2mcd\e[0me\e[3mfg", 3)
+ assert_equal [["\e[1ma\1\e[mzero\e[0m\2\e[2mb", nil, "\e[1m\e[2mc"], 2], Reline::Unicode.split_by_width("\e[1ma\1\e[mzero\e[0m\2\e[2mbc", 2)
+ end
+
def test_take_range
assert_equal 'cdef', Reline::Unicode.take_range('abcdefghi', 2, 4)
assert_equal 'あde', Reline::Unicode.take_range('abあdef', 2, 4)
- assert_equal 'zerocdef', Reline::Unicode.take_range("ab\1zero\2cdef", 2, 4)
- assert_equal 'bzerocde', Reline::Unicode.take_range("ab\1zero\2cdef", 1, 4)
+ assert_equal "\1zero\2cdef", Reline::Unicode.take_range("ab\1zero\2cdef", 2, 4)
+ assert_equal "b\1zero\2cde", Reline::Unicode.take_range("ab\1zero\2cdef", 1, 4)
assert_equal "\e[31mcd\e[42mef", Reline::Unicode.take_range("\e[31mabcd\e[42mefg", 2, 4)
assert_equal "\e]0;1\acd", Reline::Unicode.take_range("ab\e]0;1\acd", 2, 3)
assert_equal 'いう', Reline::Unicode.take_range('あいうえお', 2, 4)
@@ -62,4 +67,26 @@ class Reline::Unicode::Test < Reline::TestCase
assert_equal 10, Reline::Unicode.calculate_width('あいうえお')
assert_equal 10, Reline::Unicode.calculate_width('あいうえお', true)
end
+
+ def test_take_mbchar_range
+ assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4)
+ assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4, padding: true)
+ assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4, cover_begin: true)
+ assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4, cover_end: true)
+ assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4)
+ assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4, padding: true)
+ assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4, cover_begin: true)
+ assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4, cover_end: true)
+ assert_equal ['う', 4, 2], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4)
+ assert_equal [' う ', 3, 4], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, padding: true)
+ assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_begin: true)
+ assert_equal ['うえ', 4, 4], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_end: true)
+ assert_equal ['いう ', 2, 5], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_begin: true, padding: true)
+ assert_equal [' うえ', 3, 5], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_end: true, padding: true)
+ assert_equal [' うえお ', 3, 10], Reline::Unicode.take_mbchar_range('あいうえお', 3, 10, padding: true)
+ assert_equal [" \e[41mうえお\e[0m ", 3, 10], Reline::Unicode.take_mbchar_range("あい\e[41mうえお", 3, 10, padding: true)
+ assert_equal ["\e[41m \e[42mい\e[43m ", 1, 4], Reline::Unicode.take_mbchar_range("\e[41mあ\e[42mい\e[43mう", 1, 4, padding: true)
+ assert_equal ["\e[31mc\1ABC\2d\e[0mef", 2, 4], Reline::Unicode.take_mbchar_range("\e[31mabc\1ABC\2d\e[0mefghi", 2, 4)
+ assert_equal ["\e[41m \e[42mい\e[43m ", 1, 4], Reline::Unicode.take_mbchar_range("\e[41mあ\e[42mい\e[43mう", 1, 4, padding: true)
+ end
end
diff --git a/test/reline/test_within_pipe.rb b/test/reline/test_within_pipe.rb
index a42ca755fc..4f05255301 100644
--- a/test/reline/test_within_pipe.rb
+++ b/test/reline/test_within_pipe.rb
@@ -23,7 +23,6 @@ class Reline::WithinPipeTest < Reline::TestCase
@reader.close
@output_writer.close
@config.reset
- @config.reset_default_key_bindings
Reline.test_reset
end
diff --git a/test/reline/yamatanooroti/multiline_repl b/test/reline/yamatanooroti/multiline_repl
index 66bcf51e1a..8b82be60f4 100755
--- a/test/reline/yamatanooroti/multiline_repl
+++ b/test/reline/yamatanooroti/multiline_repl
@@ -12,7 +12,7 @@ opt = OptionParser.new
opt.on('--dynamic-prompt') {
Reline.prompt_proc = proc { |lines|
lines.each_with_index.map { |l, i|
- '[%04d]> ' % i
+ "\e[1m[%04d]>\e[m " % i
}
}
}
@@ -143,6 +143,11 @@ opt.on('--complete') {
%w{String ScriptError SyntaxError Signal}.select{ |c| c.start_with?(target) }
}
}
+opt.on('--complete-menu-with-perfect-match') {
+ Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
+ %w{abs abs2}.select{ |c| c.start_with?(target) }
+ }
+}
opt.on('--autocomplete') {
Reline.autocompletion = true
Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
@@ -217,7 +222,7 @@ rescue
end
begin
- prompt = ENV['RELINE_TEST_PROMPT'] || 'prompt> '
+ prompt = ENV['RELINE_TEST_PROMPT'] || "\e[1mprompt>\e[m "
puts 'Multiline REPL.'
while code = Reline.readmultiline(prompt, true) { |code| TerminationChecker.terminated?(code) }
case code.chomp
diff --git a/test/reline/yamatanooroti/test_rendering.rb b/test/reline/yamatanooroti/test_rendering.rb
index 09d064934a..37a1c1a193 100644
--- a/test/reline/yamatanooroti/test_rendering.rb
+++ b/test/reline/yamatanooroti/test_rendering.rb
@@ -543,15 +543,10 @@ begin
EOC
end
- def test_enable_bracketed_paste
+ def test_bracketed_paste
omit if Reline.core.io_gate.win?
- write_inputrc <<~LINES
- set enable-bracketed-paste on
- LINES
start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("\e[200~,")
- write("def hoge\n 3\nend")
- write("\e[200~.")
+ write("\e[200~def hoge\r\t3\rend\e[201~")
close
assert_screen(<<~EOC)
Multiline REPL.
@@ -561,6 +556,19 @@ begin
EOC
end
+ def test_bracketed_paste_with_undo
+ omit if Reline.core.io_gate.win?
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
+ write("abc")
+ write("\e[200~def hoge\r\t3\rend\e[201~")
+ write("\C-_")
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt> abc
+ EOC
+ end
+
def test_backspace_until_returns_to_initial
start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
write("ABC")
@@ -945,18 +953,30 @@ begin
EOC
end
- def test_with_newline
+ def test_eof_with_newline
omit if Reline.core.io_gate.win?
cmd = %Q{ruby -e 'print(%Q{abc def \\e\\r})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })'}
start_terminal(40, 50, ['bash', '-c', cmd])
sleep 1
- close
+ close rescue nil
assert_screen(<<~'EOC')
> abc def
"abc def "
EOC
end
+ def test_eof_without_newline
+ omit if Reline.core.io_gate.win?
+ cmd = %Q{ruby -e 'print(%{hello})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })'}
+ start_terminal(40, 50, ['bash', '-c', cmd])
+ sleep 1
+ close rescue nil
+ assert_screen(<<~'EOC')
+ > hello
+ "hello"
+ EOC
+ end
+
def test_em_set_mark_and_em_exchange_mark
start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
write("aaa bbb ccc ddd\M-b\M-b\M-\x20\M-b\C-x\C-xX\C-x\C-xY")
@@ -1006,6 +1026,47 @@ begin
EOC
end
+ def test_completion_menu_is_displayed_horizontally
+ start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.')
+ write("S\t\t")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> S
+ ScriptError String
+ Signal SyntaxError
+ EOC
+ end
+
+ def test_show_all_if_ambiguous_on
+ write_inputrc <<~LINES
+ set show-all-if-ambiguous on
+ LINES
+ start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.')
+ write("S\t")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> S
+ ScriptError String
+ Signal SyntaxError
+ EOC
+ end
+
+ def test_show_all_if_ambiguous_on_and_menu_with_perfect_match
+ write_inputrc <<~LINES
+ set show-all-if-ambiguous on
+ LINES
+ start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete-menu-with-perfect-match}, startup_message: 'Multiline REPL.')
+ write("a\t")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> abs
+ abs abs2
+ EOC
+ end
+
def test_simple_dialog
iterate_over_face_configs do |config_name, config_file|
start_terminal(20, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.')
@@ -1132,7 +1193,36 @@ begin
assert_screen(<<~'EOC')
Multiline REPL.
prompt> St
- r String
+ r
+ String
+ Struct
+ EOC
+ end
+
+ def test_autocomplete_target_at_end_of_line
+ start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write(' ')
+ write('Str')
+ write("\C-i")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> Str
+ ing String
+ Struct
+ EOC
+ end
+
+ def test_autocomplete_completed_input_is_wrapped
+ start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write(' ')
+ write('Str')
+ write("\C-i")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> Stri
+ ng String
Struct
EOC
end
diff --git a/test/ripper/test_parser_events.rb b/test/ripper/test_parser_events.rb
index cbae6e7ed5..dc94da01ee 100644
--- a/test/ripper/test_parser_events.rb
+++ b/test/ripper/test_parser_events.rb
@@ -269,15 +269,27 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
def test_assign_error_backref
thru_assign_error = false
result =
- parse('$` = 1', :on_assign_error) {thru_assign_error = true}
+ parse('$& = 1', :on_assign_error) {thru_assign_error = true}
assert_equal true, thru_assign_error
- assert_equal '[assign(assign_error(var_field($`)),1)]', result
+ assert_equal '[assign(assign_error(var_field($&)),1)]', result
thru_assign_error = false
result =
- parse('$`, _ = 1', :on_assign_error) {thru_assign_error = true}
+ parse('$&, _ = 1', :on_assign_error) {thru_assign_error = true}
assert_equal true, thru_assign_error
- assert_equal '[massign([assign_error(var_field($`)),var_field(_)],1)]', result
+ assert_equal '[massign([assign_error(var_field($&)),var_field(_)],1)]', result
+
+ thru_assign_error = false
+ result =
+ parse('$& += 1', :on_assign_error) {thru_assign_error = true}
+ assert_equal true, thru_assign_error
+ assert_equal '[assign_error(opassign(var_field($&),+=,1))]', result
+
+ thru_assign_error = false
+ result =
+ parse('$& += cmd 1, 2', :on_assign_error) {thru_assign_error = true}
+ assert_equal true, thru_assign_error
+ assert_equal '[assign_error(opassign(var_field($&),+=,command(cmd,[1,2])))]', result
end
def test_assign_error_const_qualified
diff --git a/test/ripper/test_ripper.rb b/test/ripper/test_ripper.rb
index 6061496d9c..f129a41be9 100644
--- a/test/ripper/test_ripper.rb
+++ b/test/ripper/test_ripper.rb
@@ -170,6 +170,14 @@ end
end;
end
+ def test_sexp_no_memory_leak
+ assert_no_memory_leak(%w(-rripper), "", "#{<<~'end;'}", rss: true)
+ 1_000_000.times do
+ Ripper.sexp("")
+ end
+ end;
+ end
+
class TestInput < self
Input = Struct.new(:lines) do
def gets
diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb
index 29da607fc5..45c6b63963 100644
--- a/test/ruby/test_ast.rb
+++ b/test/ruby/test_ast.rb
@@ -337,6 +337,8 @@ class TestAst < Test::Unit::TestCase
end
def test_node_id_for_location
+ omit if compiling_with_prism?
+
exception = begin
raise
rescue => e
@@ -356,6 +358,8 @@ class TestAst < Test::Unit::TestCase
end
def test_of_proc_and_method
+ omit if compiling_with_prism?
+
proc = Proc.new { 1 + 2 }
method = self.method(__method__)
@@ -385,6 +389,8 @@ class TestAst < Test::Unit::TestCase
end
def test_of_backtrace_location
+ omit if compiling_with_prism?
+
backtrace_location, lineno = sample_backtrace_location
node = RubyVM::AbstractSyntaxTree.of(backtrace_location)
assert_instance_of(RubyVM::AbstractSyntaxTree::Node, node)
@@ -396,6 +402,8 @@ class TestAst < Test::Unit::TestCase
end
def test_of_proc_and_method_under_eval
+ omit if compiling_with_prism?
+
keep_script_lines_back = RubyVM.keep_script_lines
RubyVM.keep_script_lines = false
@@ -425,6 +433,7 @@ class TestAst < Test::Unit::TestCase
end
def test_of_proc_and_method_under_eval_with_keep_script_lines
+ omit if compiling_with_prism?
pend if ENV['RUBY_ISEQ_DUMP_DEBUG'] # TODO
keep_script_lines_back = RubyVM.keep_script_lines
@@ -456,6 +465,8 @@ class TestAst < Test::Unit::TestCase
end
def test_of_backtrace_location_under_eval
+ omit if compiling_with_prism?
+
keep_script_lines_back = RubyVM.keep_script_lines
RubyVM.keep_script_lines = false
@@ -474,6 +485,7 @@ class TestAst < Test::Unit::TestCase
end
def test_of_backtrace_location_under_eval_with_keep_script_lines
+ omit if compiling_with_prism?
pend if ENV['RUBY_ISEQ_DUMP_DEBUG'] # TODO
keep_script_lines_back = RubyVM.keep_script_lines
@@ -736,6 +748,8 @@ dummy
end
def test_keep_script_lines_for_of
+ omit if compiling_with_prism?
+
proc = Proc.new { 1 + 2 }
method = self.method(__method__)
@@ -1238,6 +1252,24 @@ dummy
end
end
+ def test_memory_leak
+ assert_no_memory_leak([], "#{<<~"begin;"}", "\n#{<<~'end;'}", rss: true)
+ begin;
+ 1_000_000.times do
+ eval("")
+ end
+ end;
+ end
+
+ private
+
+ # We can't revisit instruction sequences to find node ids if the prism
+ # compiler was used instead of the parse.y compiler. In that case, we'll omit
+ # some tests.
+ def compiling_with_prism?
+ RubyVM::InstructionSequence.compile("").to_a[4][:parser] == :prism
+ end
+
def assert_error_tolerant(src, expected, keep_tokens: false)
begin
verbose_bak, $VERBOSE = $VERBOSE, false
diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb
index dbf91fe8c9..df4b6651b0 100644
--- a/test/ruby/test_iseq.rb
+++ b/test/ruby/test_iseq.rb
@@ -347,11 +347,17 @@ class TestISeq < Test::Unit::TestCase
end
end
assert_equal([m1, e1.message], [m2, e2.message], feature11951)
- message = e1.message.each_line
- message.with_index(1) do |line, i|
- next if /^ / =~ line
- assert_send([line, :start_with?, __FILE__],
- proc {message.map {|l, j| (i == j ? ">" : " ") + l}.join("")})
+
+ if e1.message.lines[0] == "#{__FILE__}:#{line}: syntax errors found\n"
+ # Prism lays out the error messages in line with the source, so the
+ # following assertions do not make sense in that context.
+ else
+ message = e1.message.each_line
+ message.with_index(1) do |line, i|
+ next if /^ / =~ line
+ assert_send([line, :start_with?, __FILE__],
+ proc {message.map {|l, j| (i == j ? ">" : " ") + l}.join("")})
+ end
end
end
@@ -850,4 +856,11 @@ class TestISeq < Test::Unit::TestCase
RubyVM::InstructionSequence.compile_prism(Object.new)
end
end
+
+ def test_load_from_binary_only_accepts_string_param
+ assert_raise(TypeError) do
+ var_0 = 0
+ RubyVM::InstructionSequence.load_from_binary(var_0)
+ end
+ end
end
diff --git a/test/ruby/test_m17n.rb b/test/ruby/test_m17n.rb
index 907360b3a6..a6493374b5 100644
--- a/test/ruby/test_m17n.rb
+++ b/test/ruby/test_m17n.rb
@@ -1091,7 +1091,7 @@ class TestM17N < Test::Unit::TestCase
assert_nil(e("\xa1\xa2\xa3\xa4").rindex(e("\xa3")))
s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4")
- a_with_e = /EUC-JP and ASCII-8BIT/
+ a_with_e = /EUC-JP and BINARY \(ASCII-8BIT\)/
assert_raise_with_message(Encoding::CompatibilityError, a_with_e) do
s.index(a("\xb1\xa3"))
end
@@ -1099,7 +1099,7 @@ class TestM17N < Test::Unit::TestCase
s.rindex(a("\xb1\xa3"))
end
- a_with_e = /ASCII-8BIT regexp with EUC-JP string/
+ a_with_e = /BINARY \(ASCII-8BIT\) regexp with EUC-JP string/
assert_raise_with_message(Encoding::CompatibilityError, a_with_e) do
s.index(Regexp.new(a("\xb1\xa3")))
end
diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb
index 79d9577737..bcd8892f23 100644
--- a/test/ruby/test_marshal.rb
+++ b/test/ruby/test_marshal.rb
@@ -570,13 +570,19 @@ class TestMarshal < Test::Unit::TestCase
def test_class_ivar
assert_raise(TypeError) {Marshal.load("\x04\x08Ic\x1bTestMarshal::TestClass\x06:\x0e@ivar_bug\"\x08bug")}
assert_raise(TypeError) {Marshal.load("\x04\x08IM\x1bTestMarshal::TestClass\x06:\x0e@ivar_bug\"\x08bug")}
- assert_not_operator(TestClass, :instance_variable_defined?, :@bug)
+ assert_not_operator(TestClass, :instance_variable_defined?, :@ivar_bug)
+
+ assert_raise(TypeError) {Marshal.load("\x04\x08[\x07c\x1bTestMarshal::TestClassI@\x06\x06:\x0e@ivar_bug\"\x08bug")}
+ assert_not_operator(TestClass, :instance_variable_defined?, :@ivar_bug)
end
def test_module_ivar
assert_raise(TypeError) {Marshal.load("\x04\x08Im\x1cTestMarshal::TestModule\x06:\x0e@ivar_bug\"\x08bug")}
assert_raise(TypeError) {Marshal.load("\x04\x08IM\x1cTestMarshal::TestModule\x06:\x0e@ivar_bug\"\x08bug")}
- assert_not_operator(TestModule, :instance_variable_defined?, :@bug)
+ assert_not_operator(TestModule, :instance_variable_defined?, :@ivar_bug)
+
+ assert_raise(TypeError) {Marshal.load("\x04\x08[\x07m\x1cTestMarshal::TestModuleI@\x06\x06:\x0e@ivar_bug\"\x08bug")}
+ assert_not_operator(TestModule, :instance_variable_defined?, :@ivar_bug)
end
class TestForRespondToFalse
diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb
index fe649cddb9..3857f3cc17 100644
--- a/test/ruby/test_parse.rb
+++ b/test/ruby/test_parse.rb
@@ -18,7 +18,7 @@ class TestParse < Test::Unit::TestCase
end
def test_else_without_rescue
- assert_syntax_error(<<-END, %r":#{__LINE__+2}: else without rescue"o, [__FILE__, __LINE__+1])
+ assert_syntax_error(<<-END, %r"(:#{__LINE__+2}:|#{__LINE__+2} \|.+?\n.+?\^~.+?;) else without rescue"o, [__FILE__, __LINE__+1])
begin
else
42
@@ -555,34 +555,42 @@ class TestParse < Test::Unit::TestCase
mesg = 'from the backslash through the invalid char'
e = assert_syntax_error('"\xg1"', /hex escape/)
- assert_equal(' ^~'"\n", e.message.lines.last, mesg)
+ assert_match(/(^|\| ) \^~(?!~)/, e.message.lines.last, mesg)
e = assert_syntax_error('"\u{1234"', 'unterminated Unicode escape')
- assert_equal(' ^'"\n", e.message.lines.last, mesg)
+ assert_match(/(^|\| ) \^(?!~)/, e.message.lines.last, mesg)
e = assert_syntax_error('"\u{xxxx}"', 'invalid Unicode escape')
- assert_equal(' ^'"\n", e.message.lines.last, mesg)
+ assert_match(/(^|\| ) \^(?!~)/, e.message.lines.last, mesg)
e = assert_syntax_error('"\u{xxxx', 'Unicode escape')
- assert_pattern_list([
- /.*: invalid Unicode escape\n.*\n/,
- / \^/,
- /\n/,
- /.*: unterminated Unicode escape\n.*\n/,
- / \^/,
- /\n/,
- /.*: unterminated string.*\n.*\n/,
- / \^\n/,
- ], e.message)
+ if e.message.lines.first == "#{__FILE__}:#{__LINE__ - 1}: syntax errors found\n"
+ assert_pattern_list([
+ /\s+\| \^ unterminated string;.+\n/,
+ /\s+\| \^ unterminated Unicode escape\n/,
+ /\s+\| \^ invalid Unicode escape sequence\n/,
+ ], e.message.lines[2..-1].join)
+ else
+ assert_pattern_list([
+ /.*: invalid Unicode escape\n.*\n/,
+ / \^/,
+ /\n/,
+ /.*: unterminated Unicode escape\n.*\n/,
+ / \^/,
+ /\n/,
+ /.*: unterminated string.*\n.*\n/,
+ / \^\n/,
+ ], e.message)
+ end
e = assert_syntax_error('"\M1"', /escape character syntax/)
- assert_equal(' ^~~'"\n", e.message.lines.last, mesg)
+ assert_match(/(^|\| ) \^~~(?!~)/, e.message.lines.last, mesg)
e = assert_syntax_error('"\C1"', /escape character syntax/)
- assert_equal(' ^~~'"\n", e.message.lines.last, mesg)
+ assert_match(/(^|\| ) \^~~(?!~)/, e.message.lines.last, mesg)
src = '"\xD0\u{90'"\n""000000000000000000000000"
- assert_syntax_error(src, /:#{__LINE__}: unterminated/o)
+ assert_syntax_error(src, /(:#{__LINE__}:|> #{__LINE__} \|.+) unterminated/om)
assert_syntax_error('"\u{100000000}"', /invalid Unicode escape/)
assert_equal("", eval('"\u{}"'))
@@ -605,22 +613,22 @@ class TestParse < Test::Unit::TestCase
assert_syntax_error("\"\\C-\\M-\x01\"", 'Invalid escape character syntax')
e = assert_syntax_error('"\c\u0000"', 'Invalid escape character syntax')
- assert_equal(' ^~~~'"\n", e.message.lines.last)
+ assert_match(/(^|\| ) \^~~~(?!~)/, e.message.lines.last)
e = assert_syntax_error('"\c\U0000"', 'Invalid escape character syntax')
- assert_equal(' ^~~~'"\n", e.message.lines.last)
+ assert_match(/(^|\| ) \^~~~(?!~)/, e.message.lines.last)
e = assert_syntax_error('"\C-\u0000"', 'Invalid escape character syntax')
- assert_equal(' ^~~~~'"\n", e.message.lines.last)
+ assert_match(/(^|\| ) \^~~~~(?!~)/, e.message.lines.last)
e = assert_syntax_error('"\C-\U0000"', 'Invalid escape character syntax')
- assert_equal(' ^~~~~'"\n", e.message.lines.last)
+ assert_match(/(^|\| ) \^~~~~(?!~)/, e.message.lines.last)
e = assert_syntax_error('"\M-\u0000"', 'Invalid escape character syntax')
- assert_equal(' ^~~~~'"\n", e.message.lines.last)
+ assert_match(/(^|\| ) \^~~~~(?!~)/, e.message.lines.last)
e = assert_syntax_error('"\M-\U0000"', 'Invalid escape character syntax')
- assert_equal(' ^~~~~'"\n", e.message.lines.last)
+ assert_match(/(^|\| ) \^~~~~(?!~)/, e.message.lines.last)
e = assert_syntax_error(%["\\C-\u3042"], 'Invalid escape character syntax')
- assert_match(/^\s \^(?# \\ ) ~(?# C ) ~(?# - ) ~+(?# U+3042 )$/x, e.message.lines.last)
+ assert_match(/(^|\|\s)\s \^(?# \\ ) ~(?# C ) ~(?# - ) ~+(?# U+3042 )($|\s)/x, e.message.lines.last)
assert_not_include(e.message, "invalid multibyte char")
end
@@ -875,7 +883,8 @@ x = __ENCODING__
$test_parse_foobarbazqux = nil
assert_equal(nil, $&)
assert_equal(nil, eval('alias $& $preserve_last_match'))
- assert_syntax_error('a = $#', /as a global variable name\na = \$\#\n \^~$/)
+ assert_syntax_error('a = $#', /as a global variable name/)
+ assert_syntax_error('a = $#', /a = \$\#\n(^|.+?\| ) \^~(?!~)/)
end
def test_invalid_instance_variable
@@ -1259,8 +1268,8 @@ x = __ENCODING__
assert_syntax_error("def f r:def d; def f 0end", /unexpected/)
end;
- assert_syntax_error("def\nf(000)end", /^ \^~~/)
- assert_syntax_error("def\nf(&0)end", /^ \^/)
+ assert_syntax_error("def\nf(000)end", /(^|\| ) \^~~/)
+ assert_syntax_error("def\nf(&0)end", /(^|\| ) \^/)
end
def test_method_location_in_rescue
@@ -1336,17 +1345,21 @@ x = __ENCODING__
end
def test_unexpected_token_after_numeric
- assert_syntax_error('0000xyz', /^ \^~~\Z/)
- assert_syntax_error('1.2i1.1', /^ \^~~\Z/)
- assert_syntax_error('1.2.3', /^ \^~\Z/)
+ assert_syntax_error('0000xyz', /(^|\| ) \^~~(?!~)/)
+ assert_syntax_error('1.2i1.1', /(^|\| ) \^~~(?!~)/)
+ assert_syntax_error('1.2.3', /(^|\| ) \^~(?!~)/)
assert_syntax_error('1.', /unexpected end-of-input/)
assert_syntax_error('1e', /expecting end-of-input/)
end
def test_truncated_source_line
- e = assert_syntax_error("'0123456789012345678901234567890123456789' abcdefghijklmnopqrstuvwxyz0123456789 0123456789012345678901234567890123456789",
+ lineno = __LINE__ + 1
+ e = assert_syntax_error("'0123456789012345678901234567890123456789' abcdefghijklmnopqrstuvwxyz0123456789 123456789012345678901234567890123456789",
/unexpected local variable or method/)
+
line = e.message.lines[1]
+ line.delete_prefix!("> #{lineno} | ") if line.start_with?(">")
+
assert_operator(line, :start_with?, "...")
assert_operator(line, :end_with?, "...\n")
end
@@ -1390,11 +1403,11 @@ x = __ENCODING__
end
def test_unexpected_eof
- assert_syntax_error('unless', /^ \^\Z/)
+ assert_syntax_error('unless', /(^|\| ) \^(?!~)/)
end
def test_location_of_invalid_token
- assert_syntax_error('class xxx end', /^ \^~~\Z/)
+ assert_syntax_error('class xxx end', /(^|\| ) \^~~(?!~)/)
end
def test_whitespace_warning
diff --git a/test/ruby/test_pattern_matching.rb b/test/ruby/test_pattern_matching.rb
index db6ad06b82..cfe3bd1e19 100644
--- a/test/ruby/test_pattern_matching.rb
+++ b/test/ruby/test_pattern_matching.rb
@@ -1331,7 +1331,7 @@ END
end
assert_block do
- case {}
+ case C.new({})
in {}
C.keys == nil
end
diff --git a/test/ruby/test_regexp.rb b/test/ruby/test_regexp.rb
index c996b1785a..c72029ca80 100644
--- a/test/ruby/test_regexp.rb
+++ b/test/ruby/test_regexp.rb
@@ -1827,6 +1827,14 @@ class TestRegexp < Test::Unit::TestCase
end;
end
+ def test_bug_20453
+ re = Regexp.new("^(a*)x$", timeout: 0.001)
+
+ assert_raise(Regexp::TimeoutError) do
+ re =~ "a" * 1000000 + "x"
+ end
+ end
+
def per_instance_redos_test(global_timeout, per_instance_timeout, expected_timeout)
assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}")
global_timeout = #{ EnvUtil.apply_timeout_scale(global_timeout).inspect }
diff --git a/test/ruby/test_rubyvm.rb b/test/ruby/test_rubyvm.rb
index d729aa5af8..053a914a8a 100644
--- a/test/ruby/test_rubyvm.rb
+++ b/test/ruby/test_rubyvm.rb
@@ -32,6 +32,7 @@ class TestRubyVM < Test::Unit::TestCase
end
def test_keep_script_lines
+ omit if compiling_with_prism?
pend if ENV['RUBY_ISEQ_DUMP_DEBUG'] # TODO
prev_conf = RubyVM.keep_script_lines
@@ -68,4 +69,12 @@ class TestRubyVM < Test::Unit::TestCase
ensure
RubyVM.keep_script_lines = prev_conf
end
+
+ private
+
+ # RubyVM.keep_script_lines does not mean anything in the context of prism, so
+ # we should omit tests that are looking for that functionality.
+ def compiling_with_prism?
+ RubyVM::InstructionSequence.compile("").to_a[4][:parser] == :prism
+ end
end
diff --git a/test/ruby/test_symbol.rb b/test/ruby/test_symbol.rb
index 4170f62899..41b71097d1 100644
--- a/test/ruby/test_symbol.rb
+++ b/test/ruby/test_symbol.rb
@@ -121,6 +121,7 @@ class TestSymbol < Test::Unit::TestCase
def test_inspect_under_gc_compact_stress
omit "compaction doesn't work well on s390x" if RUBY_PLATFORM =~ /s390x/ # https://github.com/ruby/ruby/pull/5077
omit "very flaky on many platforms, more so with YJIT enabled" if defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?
+ omit "very flaky on many platforms, more so with RJIT enabled" if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled?
EnvUtil.under_gc_compact_stress do
assert_inspect_evaled(':testing')
end
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb
index 44162f06cb..56b97789e5 100644
--- a/test/ruby/test_syntax.rb
+++ b/test/ruby/test_syntax.rb
@@ -889,6 +889,16 @@ e"
assert_dedented_heredoc(expect, result)
end
+ def test_dedented_heredoc_with_leading_blank_line
+ # the blank line has six leading spaces
+ result = " \n" \
+ " b\n"
+ expect = " \n" \
+ "b\n"
+ assert_dedented_heredoc(expect, result)
+ end
+
+
def test_dedented_heredoc_with_blank_more_indented_line_escaped
result = " a\n" \
"\\ \\ \\ \\ \\ \\ \n" \
@@ -996,7 +1006,7 @@ eom
end
def test_dedented_heredoc_concatenation
- assert_equal("\n0\n1", eval("<<~0 '1'\n \n0\#{}\n0"))
+ assert_equal(" \n0\n1", eval("<<~0 '1'\n \n0\#{}\n0"))
end
def test_heredoc_mixed_encoding
@@ -1238,6 +1248,20 @@ eom
assert_syntax_error("a&.x,=0", /multiple assignment destination/)
end
+ def test_safe_call_in_for_variable
+ assert_valid_syntax("for x&.bar in []; end")
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ foo = nil
+ for foo&.bar in [1]; end
+ assert_nil(foo)
+
+ foo = Struct.new(:bar).new
+ for foo&.bar in [1]; end
+ assert_equal(1, foo.bar)
+ end;
+ end
+
def test_no_warning_logop_literal
assert_warning("") do
eval("true||raise;nil")
@@ -1577,7 +1601,7 @@ eom
end
def test_syntax_error_at_newline
- expected = "\n ^"
+ expected = /(\n|\| ) \^/
assert_syntax_error("%[abcdef", expected)
assert_syntax_error("%[abcdef\n", expected)
end
@@ -1755,8 +1779,8 @@ eom
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/
+ 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)
diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb
index df71dbffc0..796787e355 100644
--- a/test/ruby/test_yjit.rb
+++ b/test/ruby/test_yjit.rb
@@ -1458,7 +1458,7 @@ class TestYJIT < Test::Unit::TestCase
end
def test_str_concat_encoding_mismatch
- assert_compiles(<<~'RUBY', result: "incompatible character encodings: ASCII-8BIT and EUC-JP")
+ assert_compiles(<<~'RUBY', result: "incompatible character encodings: BINARY (ASCII-8BIT) and EUC-JP")
def bar(a, b)
a << b
rescue => e
diff --git a/test/rubygems/helper.rb b/test/rubygems/helper.rb
index f97306717d..7014843bba 100644
--- a/test/rubygems/helper.rb
+++ b/test/rubygems/helper.rb
@@ -76,8 +76,6 @@ class Gem::TestCase < Test::Unit::TestCase
attr_accessor :uri # :nodoc:
- @@tempdirs = []
-
def assert_activate(expected, *specs)
specs.each do |spec|
case spec
@@ -451,9 +449,7 @@ class Gem::TestCase < Test::Unit::TestCase
Dir.chdir @current_dir
- FileUtils.rm_rf @tempdir
-
- restore_env
+ ENV.replace(@orig_env)
Gem::ConfigFile.send :remove_const, :SYSTEM_WIDE_CONFIG_FILE
Gem::ConfigFile.send :const_set, :SYSTEM_WIDE_CONFIG_FILE,
@@ -481,12 +477,9 @@ class Gem::TestCase < Test::Unit::TestCase
@back_ui.close
- refute_directory_exists @tempdir, "may be still in use"
- ghosts = @@tempdirs.filter_map do |test_name, tempdir|
- test_name if File.exist?(tempdir)
- end
- @@tempdirs << [method_name, @tempdir]
- assert_empty ghosts
+ FileUtils.rm_rf @tempdir
+
+ refute_directory_exists @tempdir, "#{@tempdir} used by test #{method_name} is still in use"
end
def credential_setup
@@ -541,6 +534,16 @@ class Gem::TestCase < Test::Unit::TestCase
ENV["BUNDLE_GEMFILE"] = File.join(@tempdir, "Gemfile")
end
+ def with_env(overrides, &block)
+ orig_env = ENV.to_h
+ ENV.replace(overrides)
+ begin
+ block.call
+ ensure
+ ENV.replace(orig_env)
+ end
+ end
+
##
# A git_gem is used with a gem dependencies file. The gem created here
# has no files, just a gem specification for the given +name+ and +version+.
@@ -1526,23 +1529,6 @@ Also, a list:
PUBLIC_KEY = nil
PUBLIC_CERT = nil
end if Gem::HAVE_OPENSSL
-
- private
-
- def restore_env
- unless Gem.win_platform?
- ENV.replace(@orig_env)
- return
- end
-
- # Fallback logic for Windows below to workaround
- # https://bugs.ruby-lang.org/issues/16798. Can be dropped once all
- # supported rubies include the fix for that.
-
- ENV.clear
-
- @orig_env.each {|k, v| ENV[k] = v }
- end
end
# https://github.com/seattlerb/minitest/blob/13c48a03d84a2a87855a4de0c959f96800100357/lib/minitest/mock.rb#L192
diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb
index 244b7749a5..40a473f8d6 100644
--- a/test/rubygems/test_gem.rb
+++ b/test/rubygems/test_gem.rb
@@ -516,7 +516,10 @@ class TestGem < Gem::TestCase
Gem.clear_paths
- assert_nil Gem::Specification.send(:class_variable_get, :@@all)
+ with_env("GEM_HOME" => "foo", "GEM_PATH" => "bar") do
+ assert_equal("foo", Gem.dir)
+ assert_equal("bar", Gem.path.first)
+ end
end
def test_self_configuration
@@ -1281,7 +1284,6 @@ class TestGem < Gem::TestCase
def test_self_try_activate_missing_extensions
spec = util_spec "ext", "1" do |s|
s.extensions = %w[ext/extconf.rb]
- s.mark_version
s.installed_by_version = v("2.2")
end
diff --git a/test/rubygems/test_gem_ci_detector.rb b/test/rubygems/test_gem_ci_detector.rb
index 3caefce97d..a28ee49f4b 100644
--- a/test/rubygems/test_gem_ci_detector.rb
+++ b/test/rubygems/test_gem_ci_detector.rb
@@ -3,7 +3,7 @@
require_relative "helper"
require "rubygems"
-class TestCiDetector < Test::Unit::TestCase
+class TestCiDetector < Gem::TestCase
def test_ci?
with_env("FOO" => "bar") { assert_equal(false, Gem::CIDetector.ci?) }
with_env("CI" => "true") { assert_equal(true, Gem::CIDetector.ci?) }
@@ -29,16 +29,4 @@ class TestCiDetector < Test::Unit::TestCase
assert_equal(["dsari", "taskcluster"], Gem::CIDetector.ci_strings)
end
end
-
- private
-
- def with_env(overrides, &block)
- @orig_env = ENV.to_h
- ENV.replace(overrides)
- begin
- block.call
- ensure
- ENV.replace(@orig_env)
- end
- end
end
diff --git a/test/rubygems/test_gem_commands_rebuild_command.rb b/test/rubygems/test_gem_commands_rebuild_command.rb
index 5e8c797e2d..3b7927c44e 100644
--- a/test/rubygems/test_gem_commands_rebuild_command.rb
+++ b/test/rubygems/test_gem_commands_rebuild_command.rb
@@ -105,7 +105,7 @@ class TestGemCommandsRebuildCommand < Gem::TestCase
assert_equal old_spec.name, new_spec.name
assert_equal old_spec.summary, new_spec.summary
- reproduced
+ [reproduced, original]
end
def test_build_is_reproducible
@@ -134,12 +134,21 @@ class TestGemCommandsRebuildCommand < Gem::TestCase
# also testing that `gem rebuild` overrides the value.
ENV["SOURCE_DATE_EPOCH"] = Time.new(2007, 8, 9, 10, 11, 12).to_s
- rebuild_gem_file = util_test_rebuild_gem(@gem, [@gem_name, @gem_version], original_gem_file, gemspec_file, timestamp)
+ rebuild_gem_file, saved_gem_file =
+ util_test_rebuild_gem(@gem, [@gem_name, @gem_version], original_gem_file, gemspec_file, timestamp)
rebuild_contents = File.read(rebuild_gem_file)
assert_equal build_contents, rebuild_contents
ensure
ENV["SOURCE_DATE_EPOCH"] = epoch
+ if rebuild_gem_file
+ File.unlink(rebuild_gem_file)
+ dir = File.dirname(rebuild_gem_file)
+ Dir.rmdir(dir)
+ File.unlink(saved_gem_file)
+ Dir.rmdir(File.dirname(saved_gem_file))
+ Dir.rmdir(File.dirname(dir))
+ end
end
end
diff --git a/test/rubygems/test_gem_commands_setup_command.rb b/test/rubygems/test_gem_commands_setup_command.rb
index 43f695f147..8eedb6c03a 100644
--- a/test/rubygems/test_gem_commands_setup_command.rb
+++ b/test/rubygems/test_gem_commands_setup_command.rb
@@ -159,6 +159,23 @@ class TestGemCommandsSetupCommand < Gem::TestCase
end
end
+ def test_destdir_flag_regenerates_binstubs
+ # install to destdir
+ destdir = File.join(@tempdir, "foo")
+ gem_bin_path = gem_install "destdir-only-gem", install_dir: destdir
+
+ # change binstub manually
+ write_file gem_bin_path do |io|
+ io.puts "I changed it!"
+ end
+
+ @cmd.options[:destdir] = destdir
+ @cmd.options[:prefix] = "/"
+ @cmd.execute
+
+ assert_match(/\A#!/, File.read(gem_bin_path))
+ end
+
def test_files_in
assert_equal %w[rubygems.rb rubygems/requirement.rb rubygems/ssl_certs/rubygems.org/foo.pem],
@cmd.files_in("lib").sort
@@ -412,7 +429,7 @@ class TestGemCommandsSetupCommand < Gem::TestCase
end
end
- def gem_install(name)
+ def gem_install(name, **options)
gem = util_spec name do |s|
s.executables = [name]
s.files = %W[bin/#{name}]
@@ -420,8 +437,8 @@ class TestGemCommandsSetupCommand < Gem::TestCase
write_file File.join @tempdir, "bin", name do |f|
f.puts "#!/usr/bin/ruby"
end
- install_gem gem
- File.join @gemhome, "bin", name
+ install_gem gem, **options
+ File.join options[:install_dir] || @gemhome, "bin", name
end
def gem_install_with_plugin(name)
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 b9fed0e2b0..abd1e0ae33 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
@@ -152,18 +152,18 @@ dependencies = [
[[package]]
name = "rb-sys"
-version = "0.9.94"
+version = "0.9.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06dab8dbb0beb0a575a80c4b46355c8ace1f3dc5df60a3109758f205f1061366"
+checksum = "47d30bcad206b51f2f66121190ca678dce1fdf3a2eae0ac5d838d1818b19bdf5"
dependencies = [
"rb-sys-build",
]
[[package]]
name = "rb-sys-build"
-version = "0.9.94"
+version = "0.9.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "164d44950a42f2ba2f94efdcb650e14764270f84d281352aebb261806da0b2ce"
+checksum = "3cbd92f281615f3c2dcb9dcb0f0576624752afbf9a7f99173b37c4b55b62dd8a"
dependencies = [
"bindgen",
"lazy_static",
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 9f844b62be..ad3e7f9b76 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.94"
+rb-sys = "0.9.97"
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 7e1617a663..1d174f569e 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
@@ -145,18 +145,18 @@ dependencies = [
[[package]]
name = "rb-sys"
-version = "0.9.94"
+version = "0.9.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06dab8dbb0beb0a575a80c4b46355c8ace1f3dc5df60a3109758f205f1061366"
+checksum = "47d30bcad206b51f2f66121190ca678dce1fdf3a2eae0ac5d838d1818b19bdf5"
dependencies = [
"rb-sys-build",
]
[[package]]
name = "rb-sys-build"
-version = "0.9.94"
+version = "0.9.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "164d44950a42f2ba2f94efdcb650e14764270f84d281352aebb261806da0b2ce"
+checksum = "3cbd92f281615f3c2dcb9dcb0f0576624752afbf9a7f99173b37c4b55b62dd8a"
dependencies = [
"bindgen",
"lazy_static",
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 a84cc8aabb..60cf49ce03 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.94"
+rb-sys = "0.9.97"
diff --git a/test/rubygems/test_gem_package_tar_header.rb b/test/rubygems/test_gem_package_tar_header.rb
index 4469750f9a..a3f95bb770 100644
--- a/test/rubygems/test_gem_package_tar_header.rb
+++ b/test/rubygems/test_gem_package_tar_header.rb
@@ -99,6 +99,31 @@ class TestGemPackageTarHeader < Gem::Package::TarTestCase
assert_empty @tar_header
end
+ def test_empty
+ @tar_header = Gem::Package::TarHeader.from(StringIO.new(Gem::Package::TarHeader::EMPTY_HEADER))
+
+ assert_empty @tar_header
+ assert_equal Gem::Package::TarHeader.new(
+ checksum: 0,
+ devmajor: 0,
+ devminor: 0,
+ empty: true,
+ gid: 0,
+ gname: "",
+ linkname: "",
+ magic: "",
+ mode: 0,
+ mtime: 0,
+ name: "",
+ prefix: "",
+ size: 0,
+ typeflag: "0",
+ uid: 0,
+ uname: "",
+ version: 0,
+ ), @tar_header
+ end
+
def test_equals2
assert_equal @tar_header, @tar_header
assert_equal @tar_header, @tar_header.dup
diff --git a/test/rubygems/test_gem_platform.rb b/test/rubygems/test_gem_platform.rb
index e4bf882317..00e48498c6 100644
--- a/test/rubygems/test_gem_platform.rb
+++ b/test/rubygems/test_gem_platform.rb
@@ -145,6 +145,9 @@ class TestGemPlatform < Gem::TestCase
"x86_64-openbsd3.9" => ["x86_64", "openbsd", "3.9"],
"x86_64-openbsd4.0" => ["x86_64", "openbsd", "4.0"],
"x86_64-openbsd" => ["x86_64", "openbsd", nil],
+ "wasm32-wasi" => ["wasm32", "wasi", nil],
+ "wasm32-wasip1" => ["wasm32", "wasi", nil],
+ "wasm32-wasip2" => ["wasm32", "wasi", nil],
}
test_cases.each do |arch, expected|
diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb
index 9e05649f7c..9395e34f75 100644
--- a/test/rubygems/test_gem_specification.rb
+++ b/test/rubygems/test_gem_specification.rb
@@ -56,7 +56,6 @@ end
s.add_dependency "jabber4r", "> 0.0.0"
s.add_dependency "pqa", ["> 0.4", "<= 0.6"]
- s.mark_version
s.files = %w[lib/code.rb]
end
end
@@ -69,7 +68,6 @@ end
s.license = "MIT"
s.platform = platform
- s.mark_version
s.files = %w[lib/code.rb]
s.installed_by_version = v("2.2")
end
@@ -96,7 +94,6 @@ end
s.requirements << "A working computer"
s.license = "MIT"
- s.mark_version
s.files = %w[lib/code.rb]
end
@@ -970,7 +967,10 @@ dependencies: []
def test_self_stubs_for_lazy_loading
Gem.loaded_specs.clear
- Gem::Specification.class_variable_set(:@@stubs, nil)
+
+ specification_record = Gem::Specification.specification_record
+
+ specification_record.instance_variable_set(:@stubs, nil)
dir_standard_specs = File.join Gem.dir, "specifications"
@@ -978,9 +978,9 @@ dependencies: []
save_gemspec("b-1", "1", dir_standard_specs) {|s| s.name = "b" }
assert_equal ["a-1"], Gem::Specification.stubs_for("a").map(&:full_name)
- assert_equal 1, Gem::Specification.class_variable_get(:@@stubs_by_name).length
+ assert_equal 1, specification_record.instance_variable_get(:@stubs_by_name).length
assert_equal ["b-1"], Gem::Specification.stubs_for("b").map(&:full_name)
- assert_equal 2, Gem::Specification.class_variable_get(:@@stubs_by_name).length
+ assert_equal 2, specification_record.instance_variable_get(:@stubs_by_name).length
assert_equal(
Gem::Specification.stubs_for("a").map(&:object_id),
@@ -989,7 +989,7 @@ dependencies: []
Gem.loaded_specs.delete "a"
Gem.loaded_specs.delete "b"
- Gem::Specification.class_variable_set(:@@stubs, nil)
+ specification_record.instance_variable_set(:@stubs, nil)
end
def test_self_stubs_for_no_lazy_loading_after_all_specs_setup
@@ -3187,7 +3187,7 @@ or set it to nil if you don't want to specify a license.
end
def test_removed_methods
- assert_equal Gem::Specification::REMOVED_METHODS, [:rubyforge_project=]
+ assert_equal Gem::Specification::REMOVED_METHODS, [:rubyforge_project=, :mark_version]
end
def test_validate_removed_rubyforge_project
@@ -3480,12 +3480,17 @@ Did you mean 'Ruby'?
util_setup_validate
@a1.rubygems_version = "3"
- e = assert_raise Gem::InvalidSpecificationException do
+
+ use_ui @ui do
@a1.validate
end
- assert_equal "expected RubyGems version #{Gem::VERSION}, was 3",
- e.message
+ expected = <<~EXPECTED
+ #{w}: expected RubyGems version #{Gem::VERSION}, was 3
+ #{w}: See https://guides.rubygems.org/specification-reference/ for help
+ EXPECTED
+
+ assert_equal expected, @ui.error
end
def test_validate_specification_version
diff --git a/test/rubygems/test_gem_uninstaller.rb b/test/rubygems/test_gem_uninstaller.rb
index 9e0c1aa3d8..aa5ab0ed67 100644
--- a/test/rubygems/test_gem_uninstaller.rb
+++ b/test/rubygems/test_gem_uninstaller.rb
@@ -188,22 +188,81 @@ class TestGemUninstaller < Gem::InstallerTestCase
refute File.exist?(plugin_path), "plugin not removed"
end
- def test_remove_plugins_with_install_dir
+ def test_uninstall_with_install_dir_removes_plugins
write_file File.join(@tempdir, "lib", "rubygems_plugin.rb") do |io|
io.write "# do nothing"
end
@spec.files += %w[lib/rubygems_plugin.rb]
- Gem::Installer.at(Gem::Package.build(@spec), force: true).install
+ package = Gem::Package.build(@spec)
+
+ Gem::Installer.at(package, force: true).install
plugin_path = File.join Gem.plugindir, "a_plugin.rb"
assert File.exist?(plugin_path), "plugin not written"
- Dir.mkdir "#{@gemhome}2"
- Gem::Uninstaller.new(nil, install_dir: "#{@gemhome}2").remove_plugins @spec
+ install_dir = "#{@gemhome}2"
+
+ Gem::Installer.at(package, force: true, install_dir: install_dir).install
+
+ install_dir_plugin_path = File.join install_dir, "plugins/a_plugin.rb"
+ assert File.exist?(install_dir_plugin_path), "plugin not written"
+
+ Gem::Specification.dirs = [install_dir]
+ Gem::Uninstaller.new(@spec.name, executables: true, install_dir: install_dir).uninstall
assert File.exist?(plugin_path), "plugin unintentionally removed"
+ refute File.exist?(install_dir_plugin_path), "plugin not removed"
+ end
+
+ def test_uninstall_with_install_dir_regenerates_plugins
+ write_file File.join(@tempdir, "lib", "rubygems_plugin.rb") do |io|
+ io.write "# do nothing"
+ end
+
+ @spec.files += %w[lib/rubygems_plugin.rb]
+
+ install_dir = "#{@gemhome}2"
+
+ package = Gem::Package.build(@spec)
+
+ spec_v9 = @spec.dup
+ spec_v9.version = "9"
+ package_v9 = Gem::Package.build(spec_v9)
+
+ Gem::Installer.at(package, force: true, install_dir: install_dir).install
+ Gem::Installer.at(package_v9, force: true, install_dir: install_dir).install
+
+ install_dir_plugin_path = File.join install_dir, "plugins/a_plugin.rb"
+ assert File.exist?(install_dir_plugin_path), "plugin not written"
+
+ Gem::Specification.dirs = [install_dir]
+ Gem::Uninstaller.new(@spec.name, version: "9", executables: true, install_dir: install_dir).uninstall
+ assert File.exist?(install_dir_plugin_path), "plugin unintentionally removed"
+
+ Gem::Specification.dirs = [install_dir]
+ Gem::Uninstaller.new(@spec.name, executables: true, install_dir: install_dir).uninstall
+ refute File.exist?(install_dir_plugin_path), "plugin not removed"
+ end
+
+ def test_remove_plugins_user_installed
+ write_file File.join(@tempdir, "lib", "rubygems_plugin.rb") do |io|
+ io.write "# do nothing"
+ end
+
+ @spec.files += %w[lib/rubygems_plugin.rb]
+
+ Gem::Installer.at(Gem::Package.build(@spec), force: true, user_install: true).install
+
+ plugin_path = File.join Gem.user_dir, "plugins/a_plugin.rb"
+ assert File.exist?(plugin_path), "plugin not written"
+
+ Gem::Specification.dirs = [Gem.dir, Gem.user_dir]
+
+ Gem::Uninstaller.new(@spec.name, executables: true, force: true, user_install: true).uninstall
+
+ refute File.exist?(plugin_path), "plugin not removed"
end
def test_regenerate_plugins_for
@@ -370,7 +429,7 @@ create_makefile '#{@spec.name}'
end
def test_uninstall_user_install
- @user_spec = Gem::Specification.find_by_name "b"
+ Gem::Specification.dirs = [Gem.user_dir]
uninstaller = Gem::Uninstaller.new(@user_spec.name,
executables: true,
@@ -394,6 +453,32 @@ create_makefile '#{@spec.name}'
assert_same uninstaller, @post_uninstall_hook_arg
end
+ def test_uninstall_user_install_with_symlinked_home
+ pend "Symlinks not supported or not enabled" unless symlink_supported?
+
+ Gem::Specification.dirs = [Gem.user_dir]
+
+ symlinked_home = File.join(@tempdir, "new-home")
+ FileUtils.ln_s(Gem.user_home, symlinked_home)
+
+ ENV["HOME"] = symlinked_home
+ Gem.instance_variable_set(:@user_home, nil)
+ Gem.instance_variable_set(:@data_home, nil)
+
+ uninstaller = Gem::Uninstaller.new(@user_spec.name,
+ executables: true,
+ user_install: true,
+ force: true)
+
+ gem_dir = File.join @user_spec.gem_dir
+
+ assert_path_exist gem_dir
+
+ uninstaller.uninstall
+
+ assert_path_not_exist gem_dir
+ end
+
def test_uninstall_wrong_repo
Dir.mkdir "#{@gemhome}2"
Gem.use_paths "#{@gemhome}2", [@gemhome]
diff --git a/test/rubygems/test_webauthn_poller.rb b/test/rubygems/test_webauthn_poller.rb
index 23290d8ea1..fd24081758 100644
--- a/test/rubygems/test_webauthn_poller.rb
+++ b/test/rubygems/test_webauthn_poller.rb
@@ -13,7 +13,7 @@ class WebauthnPollerTest < Gem::TestCase
@fetcher = Gem::FakeFetcher.new
Gem::RemoteFetcher.fetcher = @fetcher
@credentials = {
- email: "email@example.com",
+ identifier: "email@example.com",
password: "password",
}
end
@@ -121,4 +121,14 @@ class WebauthnPollerTest < Gem::TestCase
assert_equal error.message,
"Security device verification failed: The token in the link you used has either expired or been used already."
end
+
+ def test_poll_for_otp_missing_credentials
+ @credentials = { password: "password" }
+
+ error = assert_raise Gem::WebauthnVerificationError do
+ Gem::GemcutterUtilities::WebauthnPoller.new({}, @host).poll_for_otp(@webauthn_url, @credentials)
+ end
+
+ assert_equal error.message, "Security device verification failed: Provided missing credentials"
+ end
end
diff --git a/test/test_delegate.rb b/test/test_delegate.rb
index 57480b18ea..f7bedf37fb 100644
--- a/test/test_delegate.rb
+++ b/test/test_delegate.rb
@@ -3,14 +3,6 @@ require 'test/unit'
require 'delegate'
class TestDelegateClass < Test::Unit::TestCase
- module PP
- def mu_pp(obj)
- str = super
- str = "#<#{obj.class}: #{str}>" if Delegator === obj
- str
- end
- end
-
module M
attr_reader :m
end
@@ -215,7 +207,6 @@ class TestDelegateClass < Test::Unit::TestCase
end
def test_eql?
- extend PP
s0 = SimpleDelegator.new("foo")
s1 = SimpleDelegator.new("bar")
s2 = SimpleDelegator.new("foo")
diff --git a/test/test_ipaddr.rb b/test/test_ipaddr.rb
index e95b0d2d7a..3e5c3d2aa4 100644
--- a/test/test_ipaddr.rb
+++ b/test/test_ipaddr.rb
@@ -20,18 +20,21 @@ class TC_IPAddr < Test::Unit::TestCase
a = IPAddr.new
assert_equal("::", a.to_s)
assert_equal("0000:0000:0000:0000:0000:0000:0000:0000", a.to_string)
+ assert_equal("::/128", a.cidr)
assert_equal(Socket::AF_INET6, a.family)
assert_equal(128, a.prefix)
a = IPAddr.new("0123:4567:89ab:cdef:0ABC:DEF0:1234:5678")
assert_equal("123:4567:89ab:cdef:abc:def0:1234:5678", a.to_s)
assert_equal("0123:4567:89ab:cdef:0abc:def0:1234:5678", a.to_string)
+ assert_equal("123:4567:89ab:cdef:abc:def0:1234:5678/128", a.cidr)
assert_equal(Socket::AF_INET6, a.family)
assert_equal(128, a.prefix)
a = IPAddr.new("3ffe:505:2::/48")
assert_equal("3ffe:505:2::", a.to_s)
assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
+ assert_equal("3ffe:505:2::/48", a.cidr)
assert_equal(Socket::AF_INET6, a.family)
assert_equal(false, a.ipv4?)
assert_equal(true, a.ipv6?)
@@ -41,6 +44,7 @@ class TC_IPAddr < Test::Unit::TestCase
a = IPAddr.new("3ffe:505:2::/ffff:ffff:ffff::")
assert_equal("3ffe:505:2::", a.to_s)
assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
+ assert_equal("3ffe:505:2::/48", a.cidr)
assert_equal(Socket::AF_INET6, a.family)
assert_equal(48, a.prefix)
assert_nil(a.zone_id)
@@ -58,12 +62,14 @@ class TC_IPAddr < Test::Unit::TestCase
a = IPAddr.new("0.0.0.0")
assert_equal("0.0.0.0", a.to_s)
assert_equal("0.0.0.0", a.to_string)
+ assert_equal("0.0.0.0/32", a.cidr)
assert_equal(Socket::AF_INET, a.family)
assert_equal(32, a.prefix)
a = IPAddr.new("192.168.1.2")
assert_equal("192.168.1.2", a.to_s)
assert_equal("192.168.1.2", a.to_string)
+ assert_equal("192.168.1.2/32", a.cidr)
assert_equal(Socket::AF_INET, a.family)
assert_equal(true, a.ipv4?)
assert_equal(false, a.ipv6?)
@@ -72,6 +78,7 @@ class TC_IPAddr < Test::Unit::TestCase
a = IPAddr.new("192.168.1.2/26")
assert_equal("192.168.1.0", a.to_s)
assert_equal("192.168.1.0", a.to_string)
+ assert_equal("192.168.1.0/26", a.cidr)
assert_equal(Socket::AF_INET, a.family)
assert_equal("#<IPAddr: IPv4:192.168.1.0/255.255.255.192>", a.inspect)
assert_equal(26, a.prefix)
@@ -79,6 +86,7 @@ class TC_IPAddr < Test::Unit::TestCase
a = IPAddr.new("192.168.1.2/255.255.255.0")
assert_equal("192.168.1.0", a.to_s)
assert_equal("192.168.1.0", a.to_string)
+ assert_equal("192.168.1.0/24", a.cidr)
assert_equal(Socket::AF_INET, a.family)
assert_equal(24, a.prefix)
diff --git a/test/win32/test_registry.rb b/test/win32/test_registry.rb
new file mode 100644
index 0000000000..02cafc09b0
--- /dev/null
+++ b/test/win32/test_registry.rb
@@ -0,0 +1,97 @@
+if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM
+ 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'
+ VOLATILE_ENVIRONMENT = 'Volatile Environment'
+
+ 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_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
+ desired = Win32::Registry::KEY_ALL_ACCESS
+ option = Win32::Registry::REG_OPTION_VOLATILE
+ Win32::Registry::HKEY_CURRENT_USER.open(VOLATILE_ENVIRONMENT, desired) do |reg|
+ v = self.class.unused_value(reg)
+ begin
+ reg.create(v, desired, option) {}
+ ensure
+ reg.delete_key(v, true)
+ end
+ end
+ end
+
+ def test_write
+ desired = Win32::Registry::KEY_ALL_ACCESS
+ Win32::Registry::HKEY_CURRENT_USER.open(VOLATILE_ENVIRONMENT, desired) do |reg|
+ v = self.class.unused_value(reg)
+ begin
+ reg.write_s(v, "data")
+ assert_equal [Win32::Registry::REG_SZ, "data"], reg.read(v)
+ reg.write_i(v, 0x5fe79027)
+ assert_equal [Win32::Registry::REG_DWORD, 0x5fe79027], reg.read(v)
+ ensure
+ reg.delete(v)
+ end
+ end
+ end
+
+ private
+
+ def assert_predefined_key(key)
+ assert_kind_of Win32::Registry, key
+ assert_predicate key, :open?
+ assert_not_predicate key, :created?
+ end
+
+ class << self
+ def unused_value(reg, prefix = "Test_", limit = 100, fail: true)
+ limit.times do
+ v = + rand(0x100000).to_s(36)
+ reg.read(v)
+ rescue
+ return v
+ end
+ omit "Unused value not found in #{reg}" if fail
+ end
+ end
+ end
+end
diff --git a/test/zlib/test_zlib.rb b/test/zlib/test_zlib.rb
index 502ccceec5..15e5bd852f 100644
--- a/test/zlib/test_zlib.rb
+++ b/test/zlib/test_zlib.rb
@@ -801,7 +801,8 @@ if defined? Zlib
gz.write "hi"
gz.close
- File.open(Dir.mktmpdir, File::RDWR | File::TMPFILE) do |io|
+ tmpdir = Dir.mktmpdir("zlib_file_tmpfile")
+ File.open(tmpdir, File::RDWR | File::TMPFILE) do |io|
io.write sio.string
io.rewind
@@ -825,6 +826,8 @@ if defined? Zlib
omit 'O_TMPFILE not supported (EISDIR)'
rescue Errno::EOPNOTSUPP
omit 'O_TMPFILE not supported (EOPNOTSUPP)'
+ ensure
+ Dir.rmdir(tmpdir) if tmpdir
end
end
end
@@ -988,6 +991,25 @@ if defined? Zlib
assert_raise(ArgumentError) { f.read(-1) }
assert_equal(str, f.read)
end
+
+ Zlib::GzipReader.open(t.path) do |f|
+ s = "".b
+
+ assert_raise(ArgumentError) { f.read(-1, s) }
+
+ assert_same s, f.read(1, s)
+ assert_equal "\xE3".b, s
+
+ assert_same s, f.read(2, s)
+ assert_equal "\x81\x82".b, s
+
+ assert_same s, f.read(6, s)
+ assert_equal "\u3044\u3046".b, s
+
+ assert_nil f.read(1, s)
+ assert_equal "".b, s
+ assert_predicate f, :eof?
+ end
}
end
@@ -1002,10 +1024,14 @@ if defined? Zlib
Zlib::GzipReader.open(t.path) do |f|
s = "".dup
- f.readpartial(3, s)
+ assert_same s, f.readpartial(3, s)
assert("foo".start_with?(s))
assert_raise(ArgumentError) { f.readpartial(-1) }
+
+ assert_same s, f.readpartial(3, s)
+
+ assert_predicate f, :eof?
end
}
end
diff --git a/thread_pthread.c b/thread_pthread.c
index 82b5e362cc..b9421559f2 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -2569,10 +2569,7 @@ ubf_wakeup_thread(rb_thread_t *th)
{
RUBY_DEBUG_LOG("th:%u thread_id:%p", rb_th_serial(th), (void *)th->nt->thread_id);
- int r = pthread_kill(th->nt->thread_id, SIGVTALRM);
- if (r != 0) {
- rb_bug_errno("pthread_kill", r);
- }
+ pthread_kill(th->nt->thread_id, SIGVTALRM);
}
static void
diff --git a/tool/bundler/dev_gems.rb b/tool/bundler/dev_gems.rb
index acf7335578..1422cfc7a5 100644
--- a/tool/bundler/dev_gems.rb
+++ b/tool/bundler/dev_gems.rb
@@ -7,7 +7,7 @@ gem "rake", "~> 13.1"
gem "rb_sys"
gem "webrick", "~> 1.6"
-gem "turbo_tests", "= 2.1.0"
+gem "turbo_tests", "~> 2.2.3"
gem "parallel_tests", "< 3.9.0"
gem "parallel", "~> 1.19"
gem "rspec-core", "~> 3.12"
diff --git a/tool/lib/_tmpdir.rb b/tool/lib/_tmpdir.rb
new file mode 100644
index 0000000000..fd429dab37
--- /dev/null
+++ b/tool/lib/_tmpdir.rb
@@ -0,0 +1,100 @@
+template = "rubytest."
+
+# This path is only for tests.
+# 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.
+ #
+ # Also Rubygems creates its own temporary directory per tests, and
+ # some tests copy the full path of gemhome there. In that caes, the
+ # path contains both temporary names twice, and can exceed path name
+ # limit very easily.
+ tmp
+end
+begin
+ tmpdir = File.join(base, template + Random.new_seed.to_s(36)[-6..-1])
+ Dir.mkdir(tmpdir, 0o700)
+rescue Errno::EEXIST
+ retry
+end
+# warn "tmpdir(#{tmpdir.size}) = #{tmpdir}"
+
+pid = $$
+END {
+ if pid == $$
+ begin
+ 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"
+ 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)]
+ 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)
+ 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
+ end
+ end
+ require "fileutils"
+ FileUtils.rm_rf(tmpdir)
+ end
+ end
+}
+
+ENV["TMPDIR"] = ENV["SPEC_TEMP_DIR"] = ENV["GEM_TEST_TMPDIR"] = tmpdir
diff --git a/tool/lib/output.rb b/tool/lib/output.rb
index 5c645daca6..8cb426ae4a 100644
--- a/tool/lib/output.rb
+++ b/tool/lib/output.rb
@@ -4,10 +4,15 @@ require_relative 'colorize'
class Output
attr_reader :path, :vpath
- def initialize
- @path = @timestamp = @ifchange = @color = nil
- @overwrite = @create_only = false
- @vpath = VPath.new
+ def initialize(path: nil, timestamp: nil, ifchange: nil, color: nil,
+ overwrite: false, create_only: false, vpath: VPath.new)
+ @path = path
+ @timestamp = timestamp
+ @ifchange = ifchange
+ @color = color
+ @overwrite = overwrite
+ @create_only = create_only
+ @vpath = vpath
end
COLOR_WHEN = {
diff --git a/tool/lib/test/unit.rb b/tool/lib/test/unit.rb
index d758b5fb02..2b0856b822 100644
--- a/tool/lib/test/unit.rb
+++ b/tool/lib/test/unit.rb
@@ -37,6 +37,26 @@ module Test
class PendedError < AssertionFailedError; end
+ class << self
+ ##
+ # Extract the location where the last assertion method was
+ # called. Returns "<empty>" if _e_ does not have backtrace, or
+ # an empty string if no assertion method location was found.
+
+ def location e
+ last_before_assertion = nil
+
+ return '<empty>' unless e&.backtrace # SystemStackError can return nil.
+
+ e.backtrace.reverse_each do |s|
+ break if s =~ /:in \W(?:.*\#)?(?:assert|refute|flunk|pass|fail|raise|must|wont)/
+ last_before_assertion = s
+ end
+ return "" unless last_before_assertion
+ /:in / =~ last_before_assertion ? $` : last_before_assertion
+ end
+ end
+
module Order
class NoSort
def initialize(seed)
@@ -1778,15 +1798,7 @@ module Test
end
def location e # :nodoc:
- last_before_assertion = ""
-
- return '<empty>' unless e&.backtrace # SystemStackError can return nil.
-
- e.backtrace.reverse_each do |s|
- break if s =~ /in .(?:Test::Unit::(?:Core)?Assertions#)?(assert|refute|flunk|pass|fail|raise|must|wont)/
- last_before_assertion = s
- end
- last_before_assertion.sub(/:in .*$/, '')
+ Test::Unit.location e
end
##
diff --git a/tool/lib/test/unit/assertions.rb b/tool/lib/test/unit/assertions.rb
index b4f1dbc176..aad422f7e7 100644
--- a/tool/lib/test/unit/assertions.rb
+++ b/tool/lib/test/unit/assertions.rb
@@ -768,7 +768,14 @@ EOT
e = assert_raise(SyntaxError, mesg) do
syntax_check(src, fname, line)
end
- assert_match(error, e.message, mesg)
+
+ # Prism adds ANSI escape sequences to syntax error messages to
+ # colorize and format them. We strip them out here to make them easier
+ # to match against in tests.
+ message = e.message
+ message.gsub!(/\e\[.*?m/, "")
+
+ assert_match(error, message, mesg)
e
end
end
diff --git a/tool/lrama/lib/lrama/command.rb b/tool/lrama/lib/lrama/command.rb
index 94e86c6c94..12fc4fc7ec 100644
--- a/tool/lrama/lib/lrama/command.rb
+++ b/tool/lrama/lib/lrama/command.rb
@@ -47,6 +47,11 @@ module Lrama
puts grammar.rules
end
+ if options.trace_opts && options.trace_opts[:actions]
+ puts "Grammar rules with actions:"
+ grammar.rules.each { |rule| puts rule.with_actions }
+ end
+
File.open(options.outfile, "w+") do |f|
Lrama::Output.new(
out: f,
diff --git a/tool/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb b/tool/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb
index 1923e7819c..d8f3ae7897 100644
--- a/tool/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb
+++ b/tool/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb
@@ -13,8 +13,12 @@ module Lrama
@rules << rule
end
- def find(token)
- select_rules(token).last
+ def find_rule(token)
+ select_rules(@rules, token).last
+ end
+
+ def find_inline(token)
+ @rules.select { |rule| rule.name == token.s_value && rule.is_inline }.last
end
def created_lhs(lhs_s_value)
@@ -23,8 +27,9 @@ module Lrama
private
- def select_rules(token)
- rules = select_rules_by_name(token.rule_name)
+ 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}`"
@@ -33,8 +38,12 @@ module Lrama
end
end
- def select_rules_by_name(rule_name)
- rules = @rules.select { |rule| rule.name == rule_name }
+ 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
diff --git a/tool/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb b/tool/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb
index 7f50be873c..3eb92f8ef4 100644
--- a/tool/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb
+++ b/tool/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb
@@ -9,6 +9,28 @@ module Lrama
@user_code = nil
@precedence_sym = nil
end
+
+ def resolve_user_code(bindings)
+ return unless user_code
+
+ var_to_arg = {}
+ 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|
+ user_code.references.each do |ref|
+ if ref.name == var
+ ref.name = arg
+ end
+ end
+ end
+
+ return user_code
+ 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
index 9c1d46e4f5..38f0fca4ea 100644
--- a/tool/lrama/lib/lrama/grammar/parameterizing_rule/rule.rb
+++ b/tool/lrama/lib/lrama/grammar/parameterizing_rule/rule.rb
@@ -2,12 +2,14 @@ module Lrama
class Grammar
class ParameterizingRule
class Rule
- attr_reader :name, :parameters, :rhs_list, :required_parameters_count
+ attr_reader :name, :parameters, :rhs_list, :required_parameters_count, :tag, :is_inline
- def initialize(name, parameters, rhs_list)
+ 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
end
diff --git a/tool/lrama/lib/lrama/grammar/rule.rb b/tool/lrama/lib/lrama/grammar/rule.rb
index 9281e0574f..0e06edc80d 100644
--- a/tool/lrama/lib/lrama/grammar/rule.rb
+++ b/tool/lrama/lib/lrama/grammar/rule.rb
@@ -19,7 +19,7 @@ module Lrama
# TODO: Change this to display_name
def to_s
l = lhs.id.s_value
- r = empty_rule? ? "ε" : rhs.map {|r| r.id.s_value }.join(", ")
+ r = empty_rule? ? "ε" : rhs.map {|r| r.id.s_value }.join(" ")
"#{l} -> #{r}"
end
@@ -32,6 +32,10 @@ module Lrama
"#{l}: #{r}"
end
+ def with_actions
+ "#{to_s} {#{token_code&.s_value}}"
+ end
+
# opt_nl: ε <-- empty_rule
# | '\n' <-- not empty_rule
def empty_rule?
diff --git a/tool/lrama/lib/lrama/grammar/rule_builder.rb b/tool/lrama/lib/lrama/grammar/rule_builder.rb
index b2ccc3e243..ccb41e67f8 100644
--- a/tool/lrama/lib/lrama/grammar/rule_builder.rb
+++ b/tool/lrama/lib/lrama/grammar/rule_builder.rb
@@ -16,8 +16,13 @@ module Lrama
@user_code = nil
@precedence_sym = nil
@line = nil
+ @rules = []
@rule_builders_for_parameterizing_rules = []
@rule_builders_for_derived_rules = []
+ @rule_builders_for_inline_rules = []
+ @parameterizing_rules = []
+ @inline_rules = []
+ @midrule_action_rules = []
end
def add_rhs(rhs)
@@ -52,12 +57,16 @@ module Lrama
def setup_rules(parameterizing_rule_resolver)
preprocess_references unless @skip_preprocess_references
- process_rhs(parameterizing_rule_resolver)
+ if rhs.any? { |token| parameterizing_rule_resolver.find_inline(token) }
+ resolve_inline(parameterizing_rule_resolver)
+ else
+ process_rhs(parameterizing_rule_resolver)
+ end
build_rules
end
def rules
- @parameterizing_rules + @midrule_action_rules + @rules
+ @parameterizing_rules + @inline_rules + @midrule_action_rules + @rules
end
private
@@ -73,19 +82,25 @@ module Lrama
def build_rules
tokens = @replaced_rhs
- 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|
- rule_builder.rules
- end.flatten
- @midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder|
- rule_builder.rules
- end.flatten
- @midrule_action_rules.each do |r|
- r.original_rule = rule
+ if tokens
+ 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|
+ rule_builder.rules
+ end.flatten
+ @midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder|
+ rule_builder.rules
+ end.flatten
+ @midrule_action_rules.each do |r|
+ r.original_rule = rule
+ end
+ else
+ @inline_rules = @rule_builders_for_inline_rules.map do |rule_builder|
+ rule_builder.rules
+ end.flatten
end
end
@@ -103,7 +118,7 @@ module Lrama
when Lrama::Lexer::Token::Ident
@replaced_rhs << token
when Lrama::Lexer::Token::InstantiateRule
- parameterizing_rule = parameterizing_rule_resolver.find(token)
+ parameterizing_rule = parameterizing_rule_resolver.find_rule(token)
raise "Unexpected token. #{token}" unless parameterizing_rule
bindings = Binding.new(parameterizing_rule, token.args)
@@ -115,12 +130,12 @@ module Lrama
@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, lhs_tag: token.lhs_tag, skip_preprocess_references: true)
+ rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, lhs_tag: token.lhs_tag || parameterizing_rule.tag)
rule_builder.lhs = lhs_token
r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) }
rule_builder.line = line
rule_builder.precedence_sym = r.precedence_sym
- rule_builder.user_code = r.user_code
+ rule_builder.user_code = r.resolve_user_code(bindings)
rule_builder.complete_input
rule_builder.setup_rules(parameterizing_rule_resolver)
@rule_builders_for_parameterizing_rules << rule_builder
@@ -157,6 +172,41 @@ module Lrama
"#{token.rule_name}_#{s_values.join('_')}"
end
+ def resolve_inline(parameterizing_rule_resolver)
+ rhs.each_with_index do |token, i|
+ if inline_rule = parameterizing_rule_resolver.find_inline(token)
+ inline_rule.rhs_list.each_with_index do |inline_rhs|
+ rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, lhs_tag: lhs_tag, skip_preprocess_references: true)
+ resolve_inline_rhs(rule_builder, inline_rhs, i)
+ rule_builder.lhs = lhs
+ rule_builder.line = line
+ rule_builder.user_code = replace_inline_user_code(inline_rhs, i)
+ rule_builder.complete_input
+ rule_builder.setup_rules(parameterizing_rule_resolver)
+ @rule_builders_for_inline_rules << rule_builder
+ end
+ end
+ end
+ end
+
+ def resolve_inline_rhs(rule_builder, inline_rhs, index)
+ rhs.each_with_index do |token, i|
+ if index == i
+ inline_rhs.symbols.each { |sym| rule_builder.add_rhs(sym) }
+ else
+ rule_builder.add_rhs(token)
+ end
+ end
+ 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)
+ Lrama::Lexer::Token::UserCode.new(s_value: code, location: user_code.location)
+ end
+
def numberize_references
# Bison n'th component is 1-origin
(rhs + [user_code]).compact.each.with_index(1) do |token, i|
diff --git a/tool/lrama/lib/lrama/lexer.rb b/tool/lrama/lib/lrama/lexer.rb
index db8f384fe6..40622a51b4 100644
--- a/tool/lrama/lib/lrama/lexer.rb
+++ b/tool/lrama/lib/lrama/lexer.rb
@@ -37,6 +37,7 @@ module Lrama
%code
%rule
%no-stdlib
+ %inline
)
def initialize(grammar_file)
diff --git a/tool/lrama/lib/lrama/lexer/grammar_file.rb b/tool/lrama/lib/lrama/lexer/grammar_file.rb
index 6be0767004..3d3368625d 100644
--- a/tool/lrama/lib/lrama/lexer/grammar_file.rb
+++ b/tool/lrama/lib/lrama/lexer/grammar_file.rb
@@ -1,11 +1,21 @@
module Lrama
class Lexer
class GrammarFile
+ class Text < String
+ def inspect
+ length <= 50 ? super : "#{self[0..47]}...".inspect
+ end
+ end
+
attr_reader :path, :text
def initialize(path, text)
@path = path
- @text = text.freeze
+ @text = Text.new(text).freeze
+ end
+
+ def inspect
+ "<#{self.class}: @path=#{path}, @text=#{text.inspect}>"
end
def ==(other)
diff --git a/tool/lrama/lib/lrama/option_parser.rb b/tool/lrama/lib/lrama/option_parser.rb
index 3210b091ed..1e4d448fd1 100644
--- a/tool/lrama/lib/lrama/option_parser.rb
+++ b/tool/lrama/lib/lrama/option_parser.rb
@@ -119,8 +119,9 @@ module Lrama
VALID_TRACES = %w[
none locations scan parse automaton bitsets
- closure grammar rules resource sets muscles tools
- m4-early m4 skeleton time ielr cex all
+ closure grammar rules actions resource
+ sets muscles tools m4-early m4 skeleton time
+ ielr cex all
]
def validate_trace(trace)
diff --git a/tool/lrama/lib/lrama/parser.rb b/tool/lrama/lib/lrama/parser.rb
index 0a46f759c0..04603105b4 100644
--- a/tool/lrama/lib/lrama/parser.rb
+++ b/tool/lrama/lib/lrama/parser.rb
@@ -658,7 +658,7 @@ end
module Lrama
class Parser < Racc::Parser
-module_eval(<<'...end parser.y/module_eval...', 'parser.y', 529)
+module_eval(<<'...end parser.y/module_eval...', 'parser.y', 536)
include Lrama::Report::Duration
@@ -732,314 +732,322 @@ end
##### State transition tables begin ###
racc_action_table = [
- 96, 50, 97, 156, 155, 78, 50, 50, 156, 199,
- 78, 78, 50, 50, 199, 49, 78, 158, 69, 6,
- 3, 7, 158, 200, 210, 154, 8, 50, 200, 49,
- 40, 174, 175, 176, 47, 50, 46, 49, 53, 78,
- 74, 50, 53, 49, 159, 53, 81, 98, 56, 159,
- 201, 174, 175, 176, 94, 201, 22, 24, 25, 26,
+ 98, 51, 99, 163, 88, 79, 51, 51, 180, 163,
+ 79, 79, 51, 162, 180, 156, 79, 165, 157, 51,
+ 3, 50, 181, 165, 70, 51, 8, 50, 181, 79,
+ 75, 51, 6, 50, 7, 161, 82, 47, 51, 51,
+ 50, 50, 89, 82, 82, 166, 41, 51, 100, 50,
+ 182, 166, 82, 51, 48, 50, 182, 23, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
- 37, 46, 50, 50, 49, 49, 91, 81, 81, 50,
- 50, 49, 49, 50, 81, 49, 57, 78, 184, 58,
- 59, 22, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 9, 50, 60, 49,
- 13, 14, 15, 16, 17, 18, 61, 62, 19, 20,
- 21, 22, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 50, 50, 49,
- 49, 78, 184, 50, 50, 49, 49, 78, 184, 50,
- 50, 49, 49, 78, 184, 50, 50, 49, 49, 78,
- 184, 50, 50, 49, 49, 78, 184, 50, 50, 49,
- 49, 78, 78, 50, 50, 49, 49, 78, 78, 50,
- 50, 49, 49, 78, 78, 50, 50, 190, 49, 78,
- 78, 50, 50, 190, 49, 78, 78, 50, 50, 190,
- 49, 78, 50, 50, 49, 49, 152, 203, 153, 204,
- 174, 175, 176, 219, 221, 204, 204, 63, 64, 65,
- 66, 87, 88, 92, 94, 99, 99, 99, 101, 107,
- 111, 112, 115, 115, 115, 115, 118, 121, 122, 124,
- 126, 127, 128, 129, 130, 133, 137, 138, 139, 142,
- 143, 144, 146, 161, 163, 164, 165, 166, 167, 168,
- 169, 142, 171, 179, 180, 189, 194, 195, 197, 202,
- 189, 94, 194, 216, 218, 94, 194, 224, 94 ]
+ 37, 38, 47, 51, 51, 50, 50, 93, 79, 197,
+ 51, 51, 50, 50, 79, 197, 51, 51, 50, 50,
+ 79, 197, 23, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 9, 51, 54,
+ 50, 14, 15, 16, 17, 18, 19, 54, 54, 20,
+ 21, 22, 23, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 51, 51,
+ 50, 50, 79, 197, 51, 51, 50, 50, 79, 197,
+ 51, 51, 50, 50, 79, 197, 51, 51, 50, 50,
+ 79, 79, 51, 51, 50, 50, 79, 79, 51, 51,
+ 50, 50, 79, 79, 51, 51, 50, 207, 79, 79,
+ 51, 51, 207, 207, 79, 79, 51, 51, 50, 50,
+ 79, 187, 188, 189, 96, 187, 188, 189, 96, 217,
+ 221, 229, 218, 218, 218, 51, 51, 50, 50, 187,
+ 188, 189, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 90, 94, 96, 101, 101, 101, 103,
+ 109, 113, 114, 117, 117, 117, 117, 120, 47, 124,
+ 125, 127, 129, 130, 131, 132, 133, 136, 140, 141,
+ 142, 143, 146, 147, 148, 150, 160, 168, 170, 171,
+ 172, 173, 174, 176, 177, 178, 146, 184, 192, 193,
+ 200, 160, 204, 176, 211, 160, 215, 216, 178, 176,
+ 226, 176, 228, 96, 96, 176 ]
racc_action_check = [
- 48, 141, 48, 141, 140, 141, 170, 188, 170, 188,
- 170, 188, 207, 32, 207, 32, 207, 141, 32, 2,
- 1, 2, 170, 188, 199, 140, 3, 14, 207, 14,
- 7, 199, 199, 199, 13, 33, 9, 33, 15, 33,
- 33, 34, 16, 34, 141, 17, 34, 48, 18, 170,
- 188, 157, 157, 157, 157, 207, 9, 9, 9, 9,
+ 49, 145, 49, 145, 39, 145, 159, 183, 159, 183,
+ 159, 183, 201, 144, 201, 139, 201, 145, 139, 33,
+ 1, 33, 159, 183, 33, 34, 3, 34, 201, 34,
+ 34, 35, 2, 35, 2, 144, 35, 9, 36, 37,
+ 36, 37, 39, 36, 37, 145, 7, 38, 49, 38,
+ 159, 183, 38, 15, 14, 15, 201, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 41, 35, 36, 35, 36, 41, 35, 36, 37,
- 68, 37, 68, 165, 37, 165, 19, 165, 165, 22,
- 24, 41, 41, 41, 41, 41, 41, 41, 41, 41,
- 41, 41, 41, 41, 41, 41, 4, 69, 25, 69,
- 4, 4, 4, 4, 4, 4, 26, 27, 4, 4,
+ 9, 9, 42, 69, 172, 69, 172, 42, 172, 172,
+ 173, 70, 173, 70, 173, 173, 174, 81, 174, 81,
+ 174, 174, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 4, 82, 16,
+ 82, 4, 4, 4, 4, 4, 4, 17, 18, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 166, 80, 166,
- 80, 166, 166, 167, 81, 167, 81, 167, 167, 181,
- 107, 181, 107, 181, 181, 185, 109, 185, 109, 185,
- 185, 186, 115, 186, 115, 186, 186, 73, 74, 73,
- 74, 73, 74, 112, 114, 112, 114, 112, 114, 134,
- 159, 134, 159, 134, 159, 171, 201, 171, 201, 171,
- 201, 202, 204, 202, 204, 202, 204, 210, 117, 210,
- 117, 210, 131, 135, 131, 135, 136, 191, 136, 191,
- 192, 192, 192, 213, 217, 213, 217, 28, 29, 30,
- 31, 38, 39, 44, 45, 52, 54, 55, 56, 67,
- 71, 72, 79, 84, 85, 86, 87, 93, 94, 100,
- 102, 103, 104, 105, 106, 110, 118, 119, 120, 121,
- 122, 123, 125, 145, 147, 148, 149, 150, 151, 152,
- 153, 154, 156, 160, 162, 168, 173, 177, 187, 190,
- 197, 198, 203, 206, 211, 216, 220, 222, 224 ]
+ 4, 4, 4, 4, 4, 4, 4, 4, 194, 109,
+ 194, 109, 194, 194, 198, 111, 198, 111, 198, 198,
+ 199, 117, 199, 117, 199, 199, 74, 75, 74, 75,
+ 74, 75, 114, 116, 114, 116, 114, 116, 137, 166,
+ 137, 166, 137, 166, 182, 184, 182, 184, 182, 184,
+ 204, 216, 204, 216, 204, 216, 218, 119, 218, 119,
+ 218, 164, 164, 164, 164, 179, 179, 179, 179, 208,
+ 214, 223, 208, 214, 223, 134, 138, 134, 138, 209,
+ 209, 209, 19, 20, 23, 25, 26, 27, 28, 29,
+ 30, 31, 32, 40, 45, 46, 53, 55, 56, 57,
+ 68, 72, 73, 80, 85, 86, 87, 88, 89, 95,
+ 96, 102, 104, 105, 106, 107, 108, 112, 120, 121,
+ 122, 123, 124, 125, 126, 128, 141, 149, 151, 152,
+ 153, 154, 155, 156, 157, 158, 161, 163, 167, 169,
+ 175, 178, 180, 186, 190, 200, 205, 207, 213, 217,
+ 220, 221, 222, 226, 228, 230 ]
racc_action_pointer = [
- nil, 20, 9, 26, 97, nil, nil, 23, nil, 32,
- nil, nil, nil, 28, 24, 19, 23, 26, 43, 67,
- nil, nil, 70, nil, 71, 89, 97, 112, 212, 213,
- 214, 215, 10, 32, 38, 69, 70, 76, 216, 220,
- nil, 67, nil, nil, 200, 174, nil, nil, -5, nil,
- nil, nil, 206, nil, 207, 208, 209, nil, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, 221, 77, 104,
- nil, 224, 223, 164, 165, nil, nil, nil, nil, 224,
- 135, 141, nil, nil, 225, 226, 227, 196, nil, nil,
- nil, nil, nil, 195, 233, nil, nil, nil, nil, nil,
- 237, nil, 238, 239, 240, 241, 242, 147, nil, 153,
- 238, nil, 170, nil, 171, 159, nil, 195, 241, 236,
- 246, 204, 199, 249, nil, 250, nil, nil, nil, nil,
- nil, 199, nil, nil, 176, 200, 165, nil, nil, nil,
- -19, -2, nil, nil, nil, 233, nil, 234, 235, 236,
- 237, 238, 217, 255, 216, nil, 222, 4, nil, 177,
- 243, nil, 244, nil, nil, 80, 134, 140, 220, nil,
- 3, 182, nil, 258, nil, nil, nil, 265, nil, nil,
- nil, 146, nil, nil, nil, 152, 158, 224, 4, nil,
- 229, 166, 163, nil, nil, nil, nil, 225, 221, -16,
- nil, 183, 188, 264, 189, nil, 253, 9, nil, nil,
- 194, 272, nil, 172, nil, nil, 225, 173, nil, nil,
- 268, nil, 257, nil, 228, nil ]
+ nil, 20, 22, 26, 98, nil, nil, 39, nil, 33,
+ nil, nil, nil, nil, 48, 50, 90, 98, 99, 207,
+ 194, nil, nil, 195, nil, 196, 197, 198, 213, 214,
+ 215, 216, 217, 16, 22, 28, 35, 36, 44, -1,
+ 221, nil, 68, nil, nil, 201, 174, nil, nil, -5,
+ nil, nil, nil, 207, nil, 208, 209, 210, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, 222, 70,
+ 78, nil, 225, 224, 153, 154, nil, nil, nil, nil,
+ 225, 84, 105, nil, nil, 226, 227, 228, 197, 234,
+ nil, nil, nil, nil, nil, 197, 235, nil, nil, nil,
+ nil, nil, 239, nil, 240, 241, 242, 243, 244, 136,
+ nil, 142, 240, nil, 159, nil, 160, 148, nil, 184,
+ 243, 207, 239, 249, 206, 201, 252, nil, 253, nil,
+ nil, nil, nil, nil, 202, nil, nil, 165, 203, -26,
+ nil, 210, nil, nil, -10, -2, nil, nil, nil, 237,
+ nil, 238, 239, 240, 241, 242, 255, 259, 220, 3,
+ nil, 220, nil, 227, 143, nil, 166, 248, nil, 249,
+ nil, nil, 71, 77, 83, 228, nil, nil, 225, 147,
+ 232, nil, 171, 4, 172, nil, 265, nil, nil, nil,
+ 272, nil, nil, nil, 135, nil, nil, nil, 141, 147,
+ 229, 9, nil, nil, 177, 274, nil, 237, 158, 161,
+ nil, nil, nil, 233, 159, nil, 178, 271, 183, nil,
+ 260, 273, 262, 160, nil, nil, 232, nil, 233, nil,
+ 277, nil, nil ]
racc_action_default = [
- -2, -136, -8, -136, -136, -3, -4, -136, 226, -136,
- -9, -10, -11, -136, -136, -136, -136, -136, -136, -136,
- -23, -24, -136, -28, -136, -136, -136, -136, -136, -136,
- -136, -136, -136, -136, -136, -136, -136, -136, -136, -136,
- -7, -121, -94, -96, -136, -118, -120, -12, -125, -92,
- -93, -124, -14, -83, -15, -16, -136, -20, -25, -29,
- -32, -35, -38, -39, -40, -41, -42, -43, -49, -136,
- -52, -69, -44, -73, -136, -76, -78, -79, -133, -45,
- -86, -136, -89, -91, -46, -47, -48, -136, -5, -1,
- -95, -122, -97, -136, -136, -13, -126, -127, -128, -80,
- -136, -17, -136, -136, -136, -136, -136, -136, -53, -50,
- -71, -70, -136, -77, -74, -136, -90, -87, -136, -136,
- -136, -102, -136, -136, -84, -136, -21, -26, -30, -33,
- -36, -51, -54, -72, -75, -88, -136, -56, -6, -123,
- -98, -99, -103, -119, -81, -136, -18, -136, -136, -136,
- -136, -136, -136, -136, -102, -101, -92, -118, -107, -136,
- -136, -85, -136, -22, -27, -136, -136, -136, -60, -57,
- -100, -136, -104, -134, -111, -112, -113, -136, -110, -82,
- -19, -31, -129, -131, -132, -34, -37, -55, -58, -61,
- -92, -136, -114, -105, -135, -108, -130, -60, -118, -92,
- -65, -136, -136, -134, -136, -116, -136, -59, -62, -63,
- -136, -136, -68, -136, -106, -115, -118, -136, -66, -117,
- -134, -64, -136, -109, -118, -67 ]
+ -2, -138, -8, -138, -138, -3, -4, -138, 233, -138,
+ -9, -10, -11, -12, -138, -138, -138, -138, -138, -138,
+ -138, -24, -25, -138, -29, -138, -138, -138, -138, -138,
+ -138, -138, -138, -138, -138, -138, -138, -138, -138, -138,
+ -138, -7, -123, -96, -98, -138, -120, -122, -13, -127,
+ -94, -95, -126, -15, -85, -16, -17, -138, -21, -26,
+ -30, -33, -36, -39, -40, -41, -42, -43, -44, -50,
+ -138, -53, -71, -45, -75, -138, -78, -80, -81, -135,
+ -46, -88, -138, -91, -93, -47, -48, -49, -138, -138,
+ -5, -1, -97, -124, -99, -138, -138, -14, -128, -129,
+ -130, -82, -138, -18, -138, -138, -138, -138, -138, -138,
+ -54, -51, -73, -72, -138, -79, -76, -138, -92, -89,
+ -138, -138, -138, -138, -104, -138, -138, -86, -138, -22,
+ -27, -31, -34, -37, -52, -55, -74, -77, -90, -138,
+ -58, -62, -6, -125, -100, -101, -105, -121, -83, -138,
+ -19, -138, -138, -138, -138, -138, -136, -138, -57, -60,
+ -63, -104, -103, -94, -120, -109, -138, -138, -87, -138,
+ -23, -28, -138, -138, -138, -138, -137, -59, -62, -120,
+ -94, -67, -138, -102, -138, -106, -136, -113, -114, -115,
+ -138, -112, -84, -20, -32, -131, -133, -134, -35, -38,
+ -62, -61, -64, -65, -138, -138, -70, -94, -138, -116,
+ -107, -110, -132, -56, -138, -68, -138, -136, -138, -118,
+ -138, -136, -138, -138, -108, -117, -120, -66, -120, -119,
+ -136, -69, -111 ]
racc_goto_table = [
- 93, 75, 51, 68, 73, 193, 116, 108, 191, 173,
- 196, 1, 117, 2, 196, 196, 141, 4, 42, 41,
- 71, 89, 83, 83, 83, 83, 188, 79, 84, 85,
- 86, 52, 54, 55, 5, 214, 181, 185, 186, 213,
- 109, 113, 75, 116, 205, 114, 135, 217, 108, 170,
- 90, 209, 223, 39, 119, 207, 71, 71, 10, 11,
- 12, 116, 48, 95, 125, 162, 102, 147, 83, 83,
- 108, 103, 148, 104, 149, 105, 150, 106, 131, 151,
- 75, 67, 113, 134, 72, 110, 132, 136, 187, 211,
- 222, 123, 160, 100, 145, 71, 140, 71, 177, 206,
- 120, nil, 113, 83, nil, 83, nil, nil, nil, 157,
- nil, nil, 172, nil, nil, nil, nil, nil, nil, 71,
- nil, nil, nil, 83, nil, nil, nil, 178, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, 157, 192,
- nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
- nil, nil, nil, 208, nil, nil, 198, nil, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, nil, 212,
- 192, 220, 215, nil, nil, 198, nil, nil, 192, 225 ]
+ 76, 95, 69, 52, 74, 158, 110, 175, 118, 119,
+ 145, 208, 1, 212, 186, 2, 43, 212, 212, 4,
+ 42, 72, 91, 84, 84, 84, 84, 5, 40, 203,
+ 122, 214, 80, 85, 86, 87, 10, 210, 11, 111,
+ 115, 76, 12, 223, 138, 116, 118, 183, 110, 92,
+ 53, 55, 56, 194, 198, 199, 13, 72, 72, 219,
+ 49, 97, 128, 169, 213, 118, 104, 151, 224, 84,
+ 84, 110, 227, 105, 152, 106, 153, 107, 134, 154,
+ 76, 232, 115, 108, 137, 155, 68, 73, 112, 135,
+ 139, 121, 201, 205, 222, 126, 167, 72, 102, 72,
+ 149, 144, 190, 115, 220, 84, 123, 84, nil, nil,
+ nil, 164, nil, nil, nil, nil, nil, nil, nil, 185,
+ nil, nil, 72, nil, nil, 179, 84, nil, nil, nil,
+ nil, nil, 191, nil, 202, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, 206, 164,
+ 209, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, 179, nil, nil,
+ 209, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, 230, 209, 231, 225 ]
racc_goto_check = [
- 41, 40, 34, 32, 46, 59, 53, 33, 43, 42,
- 63, 1, 52, 2, 63, 63, 58, 3, 54, 4,
- 34, 5, 34, 34, 34, 34, 39, 31, 31, 31,
- 31, 14, 14, 14, 6, 59, 20, 20, 20, 43,
- 32, 40, 40, 53, 42, 46, 52, 43, 33, 58,
- 54, 42, 59, 7, 8, 39, 34, 34, 9, 10,
- 11, 53, 12, 13, 15, 16, 17, 18, 34, 34,
- 33, 21, 22, 23, 24, 25, 26, 27, 32, 28,
- 40, 29, 40, 46, 30, 35, 36, 37, 38, 44,
- 45, 48, 49, 50, 51, 34, 57, 34, 60, 61,
- 62, nil, 40, 34, nil, 34, nil, nil, nil, 40,
- nil, nil, 41, nil, nil, nil, nil, nil, nil, 34,
- nil, nil, nil, 34, nil, nil, nil, 40, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, 40, 40,
- nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
- nil, nil, nil, 41, nil, nil, 40, nil, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, nil, 40,
- 40, 41, 40, nil, nil, 40, nil, nil, 40, 41 ]
+ 43, 44, 33, 35, 49, 40, 34, 39, 56, 55,
+ 60, 46, 1, 64, 45, 2, 57, 64, 64, 3,
+ 4, 35, 5, 35, 35, 35, 35, 6, 7, 45,
+ 8, 46, 32, 32, 32, 32, 9, 39, 10, 33,
+ 43, 43, 11, 46, 55, 49, 56, 60, 34, 57,
+ 15, 15, 15, 21, 21, 21, 12, 35, 35, 45,
+ 13, 14, 16, 17, 40, 56, 18, 19, 39, 35,
+ 35, 34, 39, 22, 23, 24, 25, 26, 33, 27,
+ 43, 39, 43, 28, 49, 29, 30, 31, 36, 37,
+ 38, 41, 42, 47, 48, 51, 52, 35, 53, 35,
+ 54, 59, 61, 43, 62, 35, 63, 35, nil, nil,
+ nil, 43, nil, nil, nil, nil, nil, nil, nil, 44,
+ nil, nil, 35, nil, nil, 43, 35, nil, nil, nil,
+ nil, nil, 43, nil, 44, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, 43, 43,
+ 43, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, 43, nil, nil,
+ 43, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, 44, 43, 44, 43 ]
racc_goto_pointer = [
- nil, 11, 13, 15, 10, -20, 32, 47, -34, 54,
- 55, 56, 48, 15, 16, -37, -81, 9, -59, nil,
- -129, 13, -55, 14, -54, 15, -53, 16, -51, 49,
- 51, -7, -29, -61, -12, 14, -24, -31, -80, -142,
- -32, -45, -148, -163, -111, -128, -29, nil, -8, -52,
- 40, -30, -69, -74, 9, nil, nil, -25, -105, -168,
- -60, -96, 9, -171 ]
+ nil, 12, 15, 17, 11, -20, 25, 22, -60, 32,
+ 34, 38, 52, 45, 12, 34, -41, -87, 8, -62,
+ nil, -119, 14, -56, 15, -55, 16, -53, 21, -48,
+ 53, 53, -3, -31, -63, -12, 16, -23, -30, -149,
+ -136, 2, -86, -34, -45, -150, -173, -88, -121, -30,
+ nil, -6, -52, 44, -27, -73, -73, 7, nil, -23,
+ -114, -63, -107, 13, -181 ]
racc_goto_default = [
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
- 44, nil, nil, nil, nil, nil, nil, nil, nil, 23,
- nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
- nil, nil, nil, 70, 76, nil, nil, nil, nil, nil,
- 183, nil, nil, nil, nil, nil, nil, 77, nil, nil,
- nil, nil, 80, 82, nil, 43, 45, nil, nil, nil,
- nil, nil, nil, 182 ]
+ 45, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ 24, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, 71, 77, nil, nil, nil, nil,
+ nil, 46, 159, 196, nil, nil, nil, nil, nil, nil,
+ 78, nil, nil, nil, nil, 81, 83, nil, 44, nil,
+ nil, nil, nil, nil, 195 ]
racc_reduce_table = [
0, 0, :racc_error,
- 5, 54, :_reduce_none,
- 0, 55, :_reduce_none,
- 2, 55, :_reduce_none,
- 0, 60, :_reduce_4,
- 0, 61, :_reduce_5,
- 5, 59, :_reduce_6,
- 2, 59, :_reduce_none,
- 0, 56, :_reduce_8,
+ 5, 55, :_reduce_none,
+ 0, 56, :_reduce_none,
2, 56, :_reduce_none,
- 1, 62, :_reduce_none,
- 1, 62, :_reduce_none,
- 2, 62, :_reduce_12,
- 3, 62, :_reduce_none,
- 2, 62, :_reduce_none,
- 2, 62, :_reduce_15,
- 2, 62, :_reduce_16,
- 0, 68, :_reduce_17,
- 0, 69, :_reduce_18,
- 7, 62, :_reduce_19,
- 0, 70, :_reduce_20,
- 0, 71, :_reduce_21,
- 6, 62, :_reduce_22,
- 1, 62, :_reduce_23,
- 1, 62, :_reduce_none,
- 0, 74, :_reduce_25,
- 0, 75, :_reduce_26,
- 6, 63, :_reduce_27,
- 1, 63, :_reduce_none,
- 0, 76, :_reduce_29,
- 0, 77, :_reduce_30,
- 7, 63, :_reduce_31,
- 0, 78, :_reduce_32,
- 0, 79, :_reduce_33,
- 7, 63, :_reduce_34,
- 0, 80, :_reduce_35,
- 0, 81, :_reduce_36,
- 7, 63, :_reduce_37,
- 2, 63, :_reduce_38,
- 2, 63, :_reduce_39,
- 2, 63, :_reduce_40,
- 2, 63, :_reduce_41,
- 2, 63, :_reduce_42,
- 2, 72, :_reduce_none,
- 2, 72, :_reduce_44,
- 2, 72, :_reduce_45,
- 2, 72, :_reduce_46,
- 2, 72, :_reduce_47,
- 2, 72, :_reduce_48,
- 1, 82, :_reduce_49,
- 2, 82, :_reduce_50,
- 3, 82, :_reduce_51,
- 1, 85, :_reduce_52,
- 2, 85, :_reduce_53,
- 3, 86, :_reduce_54,
- 7, 64, :_reduce_55,
- 1, 90, :_reduce_56,
- 3, 90, :_reduce_57,
- 1, 91, :_reduce_58,
- 3, 91, :_reduce_59,
- 0, 92, :_reduce_60,
- 1, 92, :_reduce_61,
- 3, 92, :_reduce_62,
- 3, 92, :_reduce_63,
- 5, 92, :_reduce_64,
- 0, 97, :_reduce_65,
- 0, 98, :_reduce_66,
- 7, 92, :_reduce_67,
- 3, 92, :_reduce_68,
- 0, 88, :_reduce_none,
- 1, 88, :_reduce_none,
- 0, 89, :_reduce_none,
- 1, 89, :_reduce_none,
- 1, 83, :_reduce_73,
- 2, 83, :_reduce_74,
- 3, 83, :_reduce_75,
- 1, 99, :_reduce_76,
- 2, 99, :_reduce_77,
- 1, 93, :_reduce_none,
- 1, 93, :_reduce_none,
- 0, 101, :_reduce_80,
- 0, 102, :_reduce_81,
- 6, 67, :_reduce_82,
- 0, 103, :_reduce_83,
- 0, 104, :_reduce_84,
- 5, 67, :_reduce_85,
- 1, 84, :_reduce_86,
- 2, 84, :_reduce_87,
- 3, 84, :_reduce_88,
- 1, 105, :_reduce_89,
- 2, 105, :_reduce_90,
- 1, 106, :_reduce_none,
- 1, 87, :_reduce_92,
- 1, 87, :_reduce_93,
- 1, 57, :_reduce_none,
+ 0, 61, :_reduce_4,
+ 0, 62, :_reduce_5,
+ 5, 60, :_reduce_6,
+ 2, 60, :_reduce_none,
+ 0, 57, :_reduce_8,
2, 57, :_reduce_none,
- 1, 107, :_reduce_none,
- 2, 107, :_reduce_none,
- 4, 108, :_reduce_98,
- 1, 110, :_reduce_99,
- 3, 110, :_reduce_100,
- 2, 110, :_reduce_none,
- 0, 111, :_reduce_102,
- 1, 111, :_reduce_103,
- 3, 111, :_reduce_104,
- 4, 111, :_reduce_105,
- 6, 111, :_reduce_106,
- 0, 113, :_reduce_107,
- 0, 114, :_reduce_108,
- 8, 111, :_reduce_109,
- 3, 111, :_reduce_110,
- 1, 95, :_reduce_111,
- 1, 95, :_reduce_112,
- 1, 95, :_reduce_113,
- 1, 96, :_reduce_114,
- 3, 96, :_reduce_115,
- 2, 96, :_reduce_116,
- 4, 96, :_reduce_117,
- 0, 94, :_reduce_none,
- 3, 94, :_reduce_119,
- 1, 109, :_reduce_none,
- 0, 58, :_reduce_none,
- 0, 115, :_reduce_122,
- 3, 58, :_reduce_123,
- 1, 65, :_reduce_none,
- 0, 66, :_reduce_none,
- 1, 66, :_reduce_none,
- 1, 66, :_reduce_none,
- 1, 66, :_reduce_none,
- 1, 73, :_reduce_129,
- 2, 73, :_reduce_130,
- 1, 116, :_reduce_none,
- 1, 116, :_reduce_none,
- 1, 100, :_reduce_133,
- 0, 112, :_reduce_none,
- 1, 112, :_reduce_none ]
-
-racc_reduce_n = 136
-
-racc_shift_n = 226
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 2, 63, :_reduce_13,
+ 3, 63, :_reduce_none,
+ 2, 63, :_reduce_none,
+ 2, 63, :_reduce_16,
+ 2, 63, :_reduce_17,
+ 0, 70, :_reduce_18,
+ 0, 71, :_reduce_19,
+ 7, 63, :_reduce_20,
+ 0, 72, :_reduce_21,
+ 0, 73, :_reduce_22,
+ 6, 63, :_reduce_23,
+ 1, 63, :_reduce_24,
+ 1, 63, :_reduce_none,
+ 0, 76, :_reduce_26,
+ 0, 77, :_reduce_27,
+ 6, 64, :_reduce_28,
+ 1, 64, :_reduce_none,
+ 0, 78, :_reduce_30,
+ 0, 79, :_reduce_31,
+ 7, 64, :_reduce_32,
+ 0, 80, :_reduce_33,
+ 0, 81, :_reduce_34,
+ 7, 64, :_reduce_35,
+ 0, 82, :_reduce_36,
+ 0, 83, :_reduce_37,
+ 7, 64, :_reduce_38,
+ 2, 64, :_reduce_39,
+ 2, 64, :_reduce_40,
+ 2, 64, :_reduce_41,
+ 2, 64, :_reduce_42,
+ 2, 64, :_reduce_43,
+ 2, 74, :_reduce_none,
+ 2, 74, :_reduce_45,
+ 2, 74, :_reduce_46,
+ 2, 74, :_reduce_47,
+ 2, 74, :_reduce_48,
+ 2, 74, :_reduce_49,
+ 1, 84, :_reduce_50,
+ 2, 84, :_reduce_51,
+ 3, 84, :_reduce_52,
+ 1, 87, :_reduce_53,
+ 2, 87, :_reduce_54,
+ 3, 88, :_reduce_55,
+ 8, 65, :_reduce_56,
+ 5, 66, :_reduce_57,
+ 1, 92, :_reduce_58,
+ 3, 92, :_reduce_59,
+ 1, 94, :_reduce_60,
+ 3, 94, :_reduce_61,
+ 0, 96, :_reduce_62,
+ 1, 96, :_reduce_63,
+ 3, 96, :_reduce_64,
+ 3, 96, :_reduce_65,
+ 6, 96, :_reduce_66,
+ 0, 101, :_reduce_67,
+ 0, 102, :_reduce_68,
+ 7, 96, :_reduce_69,
+ 3, 96, :_reduce_70,
+ 0, 90, :_reduce_none,
+ 1, 90, :_reduce_none,
+ 0, 91, :_reduce_none,
+ 1, 91, :_reduce_none,
+ 1, 85, :_reduce_75,
+ 2, 85, :_reduce_76,
+ 3, 85, :_reduce_77,
+ 1, 103, :_reduce_78,
+ 2, 103, :_reduce_79,
+ 1, 97, :_reduce_none,
+ 1, 97, :_reduce_none,
+ 0, 105, :_reduce_82,
+ 0, 106, :_reduce_83,
+ 6, 69, :_reduce_84,
+ 0, 107, :_reduce_85,
+ 0, 108, :_reduce_86,
+ 5, 69, :_reduce_87,
+ 1, 86, :_reduce_88,
+ 2, 86, :_reduce_89,
+ 3, 86, :_reduce_90,
+ 1, 109, :_reduce_91,
+ 2, 109, :_reduce_92,
+ 1, 110, :_reduce_none,
+ 1, 89, :_reduce_94,
+ 1, 89, :_reduce_95,
+ 1, 58, :_reduce_none,
+ 2, 58, :_reduce_none,
+ 1, 111, :_reduce_none,
+ 2, 111, :_reduce_none,
+ 4, 112, :_reduce_100,
+ 1, 113, :_reduce_101,
+ 3, 113, :_reduce_102,
+ 2, 113, :_reduce_none,
+ 0, 114, :_reduce_104,
+ 1, 114, :_reduce_105,
+ 3, 114, :_reduce_106,
+ 4, 114, :_reduce_107,
+ 6, 114, :_reduce_108,
+ 0, 115, :_reduce_109,
+ 0, 116, :_reduce_110,
+ 8, 114, :_reduce_111,
+ 3, 114, :_reduce_112,
+ 1, 99, :_reduce_113,
+ 1, 99, :_reduce_114,
+ 1, 99, :_reduce_115,
+ 1, 100, :_reduce_116,
+ 3, 100, :_reduce_117,
+ 2, 100, :_reduce_118,
+ 4, 100, :_reduce_119,
+ 0, 98, :_reduce_none,
+ 3, 98, :_reduce_121,
+ 1, 95, :_reduce_none,
+ 0, 59, :_reduce_none,
+ 0, 117, :_reduce_124,
+ 3, 59, :_reduce_125,
+ 1, 67, :_reduce_none,
+ 0, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 75, :_reduce_131,
+ 2, 75, :_reduce_132,
+ 1, 118, :_reduce_none,
+ 1, 118, :_reduce_none,
+ 1, 104, :_reduce_135,
+ 0, 93, :_reduce_none,
+ 1, 93, :_reduce_none ]
+
+racc_reduce_n = 138
+
+racc_shift_n = 233
racc_token_table = {
false => 0,
@@ -1085,18 +1093,19 @@ racc_token_table = {
"(" => 40,
")" => 41,
":" => 42,
- "," => 43,
- "|" => 44,
- "%empty" => 45,
- "%prec" => 46,
- "?" => 47,
- "+" => 48,
- "*" => 49,
- "[" => 50,
- "]" => 51,
- "{...}" => 52 }
-
-racc_nt_base = 53
+ "%inline" => 43,
+ "," => 44,
+ "|" => 45,
+ "%empty" => 46,
+ "%prec" => 47,
+ "?" => 48,
+ "+" => 49,
+ "*" => 50,
+ "[" => 51,
+ "]" => 52,
+ "{...}" => 53 }
+
+racc_nt_base = 54
racc_use_result_var = true
@@ -1161,6 +1170,7 @@ Racc_token_to_s_table = [
"\"(\"",
"\")\"",
"\":\"",
+ "\"%inline\"",
"\",\"",
"\"|\"",
"\"%empty\"",
@@ -1183,6 +1193,7 @@ Racc_token_to_s_table = [
"bison_declaration",
"grammar_declaration",
"rule_declaration",
+ "inline_declaration",
"variable",
"value",
"params",
@@ -1209,7 +1220,9 @@ Racc_token_to_s_table = [
"int_opt",
"alias",
"rule_args",
+ "tag_opt",
"rule_rhs_list",
+ "id_colon",
"rule_rhs",
"symbol",
"named_ref_opt",
@@ -1227,10 +1240,8 @@ Racc_token_to_s_table = [
"token_declaration_for_precedence",
"rules_or_grammar_declaration",
"rules",
- "id_colon",
"rhs_list",
"rhs",
- "tag_opt",
"@21",
"@22",
"@23",
@@ -1289,19 +1300,21 @@ module_eval(<<'.,.,', 'parser.y', 27)
# reduce 11 omitted
-module_eval(<<'.,.,', 'parser.y', 32)
- def _reduce_12(val, _values, result)
+# reduce 12 omitted
+
+module_eval(<<'.,.,', 'parser.y', 33)
+ def _reduce_13(val, _values, result)
@grammar.expect = val[1]
result
end
.,.,
-# reduce 13 omitted
-
# reduce 14 omitted
-module_eval(<<'.,.,', 'parser.y', 37)
- def _reduce_15(val, _values, result)
+# reduce 15 omitted
+
+module_eval(<<'.,.,', 'parser.y', 38)
+ def _reduce_16(val, _values, result)
val[1].each {|token|
@grammar.lex_param = Grammar::Code::NoReferenceCode.new(type: :lex_param, token_code: token).token_code.s_value
}
@@ -1310,8 +1323,8 @@ module_eval(<<'.,.,', 'parser.y', 37)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 43)
- def _reduce_16(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 44)
+ def _reduce_17(val, _values, result)
val[1].each {|token|
@grammar.parse_param = Grammar::Code::NoReferenceCode.new(type: :parse_param, token_code: token).token_code.s_value
}
@@ -1320,81 +1333,81 @@ module_eval(<<'.,.,', 'parser.y', 43)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 49)
- def _reduce_17(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 50)
+ def _reduce_18(val, _values, result)
begin_c_declaration("}")
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 53)
- def _reduce_18(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 54)
+ def _reduce_19(val, _values, result)
end_c_declaration
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 57)
- def _reduce_19(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 58)
+ def _reduce_20(val, _values, result)
@grammar.add_percent_code(id: val[1], code: val[4])
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 61)
- def _reduce_20(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 62)
+ def _reduce_21(val, _values, result)
begin_c_declaration("}")
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 65)
- def _reduce_21(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 66)
+ def _reduce_22(val, _values, result)
end_c_declaration
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 69)
- def _reduce_22(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 70)
+ def _reduce_23(val, _values, result)
@grammar.initial_action = Grammar::Code::InitialActionCode.new(type: :initial_action, token_code: val[3])
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 71)
- def _reduce_23(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 72)
+ def _reduce_24(val, _values, result)
@grammar.no_stdlib = true
result
end
.,.,
-# reduce 24 omitted
+# reduce 25 omitted
-module_eval(<<'.,.,', 'parser.y', 76)
- def _reduce_25(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 77)
+ def _reduce_26(val, _values, result)
begin_c_declaration("}")
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 80)
- def _reduce_26(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 81)
+ def _reduce_27(val, _values, result)
end_c_declaration
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 84)
- def _reduce_27(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 85)
+ def _reduce_28(val, _values, result)
@grammar.set_union(
Grammar::Code::NoReferenceCode.new(type: :union, token_code: val[3]),
val[3].line
@@ -1404,26 +1417,26 @@ module_eval(<<'.,.,', 'parser.y', 84)
end
.,.,
-# reduce 28 omitted
+# reduce 29 omitted
-module_eval(<<'.,.,', 'parser.y', 92)
- def _reduce_29(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 93)
+ def _reduce_30(val, _values, result)
begin_c_declaration("}")
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 96)
- def _reduce_30(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 97)
+ def _reduce_31(val, _values, result)
end_c_declaration
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 100)
- def _reduce_31(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 101)
+ def _reduce_32(val, _values, result)
@grammar.add_destructor(
ident_or_tags: val[6],
token_code: val[3],
@@ -1434,24 +1447,24 @@ module_eval(<<'.,.,', 'parser.y', 100)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 108)
- def _reduce_32(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 109)
+ def _reduce_33(val, _values, result)
begin_c_declaration("}")
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 112)
- def _reduce_33(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 113)
+ def _reduce_34(val, _values, result)
end_c_declaration
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 116)
- def _reduce_34(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 117)
+ def _reduce_35(val, _values, result)
@grammar.add_printer(
ident_or_tags: val[6],
token_code: val[3],
@@ -1462,24 +1475,24 @@ module_eval(<<'.,.,', 'parser.y', 116)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 124)
- def _reduce_35(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 125)
+ def _reduce_36(val, _values, result)
begin_c_declaration("}")
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 128)
- def _reduce_36(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 129)
+ def _reduce_37(val, _values, result)
end_c_declaration
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 132)
- def _reduce_37(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 133)
+ def _reduce_38(val, _values, result)
@grammar.add_error_token(
ident_or_tags: val[6],
token_code: val[3],
@@ -1490,50 +1503,50 @@ module_eval(<<'.,.,', 'parser.y', 132)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 140)
- def _reduce_38(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 141)
+ def _reduce_39(val, _values, result)
@grammar.after_shift = val[1]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 144)
- def _reduce_39(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 145)
+ def _reduce_40(val, _values, result)
@grammar.before_reduce = val[1]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 148)
- def _reduce_40(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 149)
+ def _reduce_41(val, _values, result)
@grammar.after_reduce = val[1]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 152)
- def _reduce_41(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 153)
+ def _reduce_42(val, _values, result)
@grammar.after_shift_error_token = val[1]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 156)
- def _reduce_42(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 157)
+ def _reduce_43(val, _values, result)
@grammar.after_pop_stack = val[1]
result
end
.,.,
-# reduce 43 omitted
+# reduce 44 omitted
-module_eval(<<'.,.,', 'parser.y', 162)
- def _reduce_44(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 163)
+ def _reduce_45(val, _values, result)
val[1].each {|hash|
hash[:tokens].each {|id|
@grammar.add_type(id: id, tag: hash[:tag])
@@ -1544,8 +1557,8 @@ module_eval(<<'.,.,', 'parser.y', 162)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 170)
- def _reduce_45(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 171)
+ def _reduce_46(val, _values, result)
val[1].each {|hash|
hash[:tokens].each {|id|
sym = @grammar.add_term(id: id)
@@ -1558,8 +1571,8 @@ module_eval(<<'.,.,', 'parser.y', 170)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 180)
- def _reduce_46(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 181)
+ def _reduce_47(val, _values, result)
val[1].each {|hash|
hash[:tokens].each {|id|
sym = @grammar.add_term(id: id)
@@ -1572,8 +1585,8 @@ module_eval(<<'.,.,', 'parser.y', 180)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 190)
- def _reduce_47(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 191)
+ def _reduce_48(val, _values, result)
val[1].each {|hash|
hash[:tokens].each {|id|
sym = @grammar.add_term(id: id)
@@ -1586,8 +1599,8 @@ module_eval(<<'.,.,', 'parser.y', 190)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 200)
- def _reduce_48(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 201)
+ def _reduce_49(val, _values, result)
val[1].each {|hash|
hash[:tokens].each {|id|
sym = @grammar.add_term(id: id)
@@ -1600,8 +1613,8 @@ module_eval(<<'.,.,', 'parser.y', 200)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 211)
- def _reduce_49(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 212)
+ def _reduce_50(val, _values, result)
val[0].each {|token_declaration|
@grammar.add_term(id: token_declaration[0], alias_name: token_declaration[2], token_id: token_declaration[1], tag: nil, replace: true)
}
@@ -1610,8 +1623,8 @@ module_eval(<<'.,.,', 'parser.y', 211)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 217)
- def _reduce_50(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 218)
+ def _reduce_51(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)
}
@@ -1620,8 +1633,8 @@ module_eval(<<'.,.,', 'parser.y', 217)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 223)
- def _reduce_51(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 224)
+ def _reduce_52(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)
}
@@ -1630,52 +1643,61 @@ module_eval(<<'.,.,', 'parser.y', 223)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 228)
- def _reduce_52(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 229)
+ def _reduce_53(val, _values, result)
result = [val[0]]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 229)
- def _reduce_53(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 230)
+ def _reduce_54(val, _values, result)
result = val[0].append(val[1])
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 231)
- def _reduce_54(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 232)
+ def _reduce_55(val, _values, result)
result = val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 235)
- def _reduce_55(val, _values, result)
- rule = Grammar::ParameterizingRule::Rule.new(val[1].s_value, val[3], val[6])
+module_eval(<<'.,.,', 'parser.y', 236)
+ def _reduce_56(val, _values, result)
+ rule = Grammar::ParameterizingRule::Rule.new(val[1].s_value, val[3], val[7], tag: val[5])
@grammar.add_parameterizing_rule(rule)
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 239)
- def _reduce_56(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 242)
+ def _reduce_57(val, _values, result)
+ rule = Grammar::ParameterizingRule::Rule.new(val[2].s_value, [], val[4], is_inline: true)
+ @grammar.add_parameterizing_rule(rule)
+
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'parser.y', 246)
+ def _reduce_58(val, _values, result)
result = [val[0]]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 240)
- def _reduce_57(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 247)
+ def _reduce_59(val, _values, result)
result = val[0].append(val[2])
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 244)
- def _reduce_58(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 251)
+ def _reduce_60(val, _values, result)
builder = val[0]
result = [builder]
@@ -1683,8 +1705,8 @@ module_eval(<<'.,.,', 'parser.y', 244)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 249)
- def _reduce_59(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 256)
+ def _reduce_61(val, _values, result)
builder = val[2]
result = val[0].append(builder)
@@ -1692,8 +1714,8 @@ module_eval(<<'.,.,', 'parser.y', 249)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 255)
- def _reduce_60(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 262)
+ def _reduce_62(val, _values, result)
reset_precs
result = Grammar::ParameterizingRule::Rhs.new
@@ -1701,8 +1723,8 @@ module_eval(<<'.,.,', 'parser.y', 255)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 260)
- def _reduce_61(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 267)
+ def _reduce_63(val, _values, result)
reset_precs
result = Grammar::ParameterizingRule::Rhs.new
@@ -1710,8 +1732,8 @@ module_eval(<<'.,.,', 'parser.y', 260)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 265)
- def _reduce_62(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 272)
+ def _reduce_64(val, _values, result)
token = val[1]
token.alias_name = val[2]
builder = val[0]
@@ -1722,8 +1744,8 @@ module_eval(<<'.,.,', 'parser.y', 265)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 273)
- def _reduce_63(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 280)
+ def _reduce_65(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
@@ -1732,18 +1754,18 @@ module_eval(<<'.,.,', 'parser.y', 273)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 279)
- def _reduce_64(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 286)
+ def _reduce_66(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])
+ 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
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 285)
- def _reduce_65(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 292)
+ def _reduce_67(val, _values, result)
if @prec_seen
on_action_error("multiple User_code after %prec", val[0]) if @code_after_prec
@code_after_prec = true
@@ -1754,16 +1776,16 @@ module_eval(<<'.,.,', 'parser.y', 285)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 293)
- def _reduce_66(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 300)
+ def _reduce_68(val, _values, result)
end_c_declaration
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 297)
- def _reduce_67(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 304)
+ def _reduce_69(val, _values, result)
user_code = val[3]
user_code.alias_name = val[6]
builder = val[0]
@@ -1774,8 +1796,8 @@ module_eval(<<'.,.,', 'parser.y', 297)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 305)
- def _reduce_68(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 312)
+ def _reduce_70(val, _values, result)
sym = @grammar.find_symbol_by_id!(val[2])
@prec_seen = true
builder = val[0]
@@ -1786,168 +1808,168 @@ module_eval(<<'.,.,', 'parser.y', 305)
end
.,.,
-# reduce 69 omitted
-
-# reduce 70 omitted
-
# reduce 71 omitted
# reduce 72 omitted
-module_eval(<<'.,.,', 'parser.y', 320)
- def _reduce_73(val, _values, result)
+# reduce 73 omitted
+
+# reduce 74 omitted
+
+module_eval(<<'.,.,', 'parser.y', 327)
+ def _reduce_75(val, _values, result)
result = [{tag: nil, tokens: val[0]}]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 324)
- def _reduce_74(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 331)
+ def _reduce_76(val, _values, result)
result = [{tag: val[0], tokens: val[1]}]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 328)
- def _reduce_75(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 335)
+ def _reduce_77(val, _values, result)
result = val[0].append({tag: val[1], tokens: val[2]})
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 331)
- def _reduce_76(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 338)
+ def _reduce_78(val, _values, result)
result = [val[0]]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 332)
- def _reduce_77(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 339)
+ def _reduce_79(val, _values, result)
result = val[0].append(val[1])
result
end
.,.,
-# reduce 78 omitted
+# reduce 80 omitted
-# reduce 79 omitted
+# reduce 81 omitted
-module_eval(<<'.,.,', 'parser.y', 339)
- def _reduce_80(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 346)
+ def _reduce_82(val, _values, result)
begin_c_declaration("}")
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 343)
- def _reduce_81(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 350)
+ def _reduce_83(val, _values, result)
end_c_declaration
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 347)
- def _reduce_82(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 354)
+ def _reduce_84(val, _values, result)
result = val[0].append(val[3])
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 351)
- def _reduce_83(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 358)
+ def _reduce_85(val, _values, result)
begin_c_declaration("}")
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 355)
- def _reduce_84(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 362)
+ def _reduce_86(val, _values, result)
end_c_declaration
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 359)
- def _reduce_85(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 366)
+ def _reduce_87(val, _values, result)
result = [val[2]]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 364)
- def _reduce_86(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 371)
+ def _reduce_88(val, _values, result)
result = [{tag: nil, tokens: val[0]}]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 368)
- def _reduce_87(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 375)
+ def _reduce_89(val, _values, result)
result = [{tag: val[0], tokens: val[1]}]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 372)
- def _reduce_88(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 379)
+ def _reduce_90(val, _values, result)
result = val[0].append({tag: val[1], tokens: val[2]})
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 375)
- def _reduce_89(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 382)
+ def _reduce_91(val, _values, result)
result = [val[0]]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 376)
- def _reduce_90(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 383)
+ def _reduce_92(val, _values, result)
result = val[0].append(val[1])
result
end
.,.,
-# reduce 91 omitted
+# reduce 93 omitted
-module_eval(<<'.,.,', 'parser.y', 380)
- def _reduce_92(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 387)
+ def _reduce_94(val, _values, result)
on_action_error("ident after %prec", val[0]) if @prec_seen
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 381)
- def _reduce_93(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 388)
+ def _reduce_95(val, _values, result)
on_action_error("char after %prec", val[0]) if @prec_seen
result
end
.,.,
-# reduce 94 omitted
-
-# reduce 95 omitted
-
# reduce 96 omitted
# reduce 97 omitted
-module_eval(<<'.,.,', 'parser.y', 391)
- def _reduce_98(val, _values, result)
+# reduce 98 omitted
+
+# reduce 99 omitted
+
+module_eval(<<'.,.,', 'parser.y', 398)
+ def _reduce_100(val, _values, result)
lhs = val[0]
lhs.alias_name = val[1]
val[3].each do |builder|
@@ -1960,8 +1982,8 @@ module_eval(<<'.,.,', 'parser.y', 391)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 402)
- def _reduce_99(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 409)
+ def _reduce_101(val, _values, result)
builder = val[0]
if !builder.line
builder.line = @lexer.line - 1
@@ -1972,8 +1994,8 @@ module_eval(<<'.,.,', 'parser.y', 402)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 410)
- def _reduce_100(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 417)
+ def _reduce_102(val, _values, result)
builder = val[2]
if !builder.line
builder.line = @lexer.line - 1
@@ -1984,10 +2006,10 @@ module_eval(<<'.,.,', 'parser.y', 410)
end
.,.,
-# reduce 101 omitted
+# reduce 103 omitted
-module_eval(<<'.,.,', 'parser.y', 420)
- def _reduce_102(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 427)
+ def _reduce_104(val, _values, result)
reset_precs
result = Grammar::RuleBuilder.new(@rule_counter, @midrule_action_counter)
@@ -1995,8 +2017,8 @@ module_eval(<<'.,.,', 'parser.y', 420)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 425)
- def _reduce_103(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 432)
+ def _reduce_105(val, _values, result)
reset_precs
result = Grammar::RuleBuilder.new(@rule_counter, @midrule_action_counter)
@@ -2004,8 +2026,8 @@ module_eval(<<'.,.,', 'parser.y', 425)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 430)
- def _reduce_104(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 437)
+ def _reduce_106(val, _values, result)
token = val[1]
token.alias_name = val[2]
builder = val[0]
@@ -2016,8 +2038,8 @@ module_eval(<<'.,.,', 'parser.y', 430)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 438)
- def _reduce_105(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 445)
+ def _reduce_107(val, _values, result)
token = Lrama::Lexer::Token::InstantiateRule.new(s_value: val[2], location: @lexer.location, args: [val[1]], lhs_tag: val[3])
builder = val[0]
builder.add_rhs(token)
@@ -2028,8 +2050,8 @@ module_eval(<<'.,.,', 'parser.y', 438)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 446)
- def _reduce_106(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 453)
+ def _reduce_108(val, _values, result)
token = Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, location: @lexer.location, args: val[3], lhs_tag: val[5])
builder = val[0]
builder.add_rhs(token)
@@ -2040,8 +2062,8 @@ module_eval(<<'.,.,', 'parser.y', 446)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 454)
- def _reduce_107(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 461)
+ def _reduce_109(val, _values, result)
if @prec_seen
on_action_error("multiple User_code after %prec", val[0]) if @code_after_prec
@code_after_prec = true
@@ -2052,16 +2074,16 @@ module_eval(<<'.,.,', 'parser.y', 454)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 462)
- def _reduce_108(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 469)
+ def _reduce_110(val, _values, result)
end_c_declaration
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 466)
- def _reduce_109(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 473)
+ def _reduce_111(val, _values, result)
user_code = val[3]
user_code.alias_name = val[6]
user_code.tag = val[7]
@@ -2073,8 +2095,8 @@ module_eval(<<'.,.,', 'parser.y', 466)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 475)
- def _reduce_110(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 482)
+ def _reduce_112(val, _values, result)
sym = @grammar.find_symbol_by_id!(val[2])
@prec_seen = true
builder = val[0]
@@ -2085,70 +2107,70 @@ module_eval(<<'.,.,', 'parser.y', 475)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 482)
- def _reduce_111(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 489)
+ def _reduce_113(val, _values, result)
result = "option"
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 483)
- def _reduce_112(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 490)
+ def _reduce_114(val, _values, result)
result = "nonempty_list"
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 484)
- def _reduce_113(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 491)
+ def _reduce_115(val, _values, result)
result = "list"
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 486)
- def _reduce_114(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 493)
+ def _reduce_116(val, _values, result)
result = [val[0]]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 487)
- def _reduce_115(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 494)
+ def _reduce_117(val, _values, result)
result = val[0].append(val[2])
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 488)
- def _reduce_116(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 495)
+ def _reduce_118(val, _values, result)
result = [Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, location: @lexer.location, args: val[0])]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 489)
- def _reduce_117(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 496)
+ def _reduce_119(val, _values, result)
result = [Lrama::Lexer::Token::InstantiateRule.new(s_value: val[0].s_value, location: @lexer.location, args: val[2])]
result
end
.,.,
-# reduce 118 omitted
+# reduce 120 omitted
-module_eval(<<'.,.,', 'parser.y', 492)
- def _reduce_119(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 499)
+ def _reduce_121(val, _values, result)
result = val[1].s_value
result
end
.,.,
-# reduce 120 omitted
+# reduce 122 omitted
-# reduce 121 omitted
+# reduce 123 omitted
-module_eval(<<'.,.,', 'parser.y', 499)
- def _reduce_122(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 506)
+ def _reduce_124(val, _values, result)
begin_c_declaration('\Z')
@grammar.epilogue_first_lineno = @lexer.line + 1
@@ -2156,8 +2178,8 @@ module_eval(<<'.,.,', 'parser.y', 499)
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 504)
- def _reduce_123(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 511)
+ def _reduce_125(val, _values, result)
end_c_declaration
@grammar.epilogue = val[2].s_value
@@ -2165,44 +2187,44 @@ module_eval(<<'.,.,', 'parser.y', 504)
end
.,.,
-# reduce 124 omitted
-
-# reduce 125 omitted
-
# reduce 126 omitted
# reduce 127 omitted
# reduce 128 omitted
-module_eval(<<'.,.,', 'parser.y', 515)
- def _reduce_129(val, _values, result)
+# reduce 129 omitted
+
+# reduce 130 omitted
+
+module_eval(<<'.,.,', 'parser.y', 522)
+ def _reduce_131(val, _values, result)
result = [val[0]]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 516)
- def _reduce_130(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 523)
+ def _reduce_132(val, _values, result)
result = val[0].append(val[1])
result
end
.,.,
-# reduce 131 omitted
+# reduce 133 omitted
-# reduce 132 omitted
+# reduce 134 omitted
-module_eval(<<'.,.,', 'parser.y', 521)
- def _reduce_133(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 528)
+ def _reduce_135(val, _values, result)
result = Lrama::Lexer::Token::Ident.new(s_value: val[0])
result
end
.,.,
-# reduce 134 omitted
+# reduce 136 omitted
-# reduce 135 omitted
+# reduce 137 omitted
def _reduce_none(val, _values, result)
val[0]
diff --git a/tool/lrama/lib/lrama/state.rb b/tool/lrama/lib/lrama/state.rb
index 45bfe5acf6..ceb74d856a 100644
--- a/tool/lrama/lib/lrama/state.rb
+++ b/tool/lrama/lib/lrama/state.rb
@@ -70,38 +70,16 @@ module Lrama
reduce.look_ahead = look_ahead
end
- # Returns array of [Shift, next_state]
def nterm_transitions
- return @nterm_transitions if @nterm_transitions
-
- @nterm_transitions = []
-
- shifts.each do |shift|
- next if shift.next_sym.term?
-
- @nterm_transitions << [shift, @items_to_state[shift.next_items]]
- end
-
- @nterm_transitions
+ @nterm_transitions ||= transitions.select {|shift, _| shift.next_sym.nterm? }
end
- # Returns array of [Shift, next_state]
def term_transitions
- return @term_transitions if @term_transitions
-
- @term_transitions = []
-
- shifts.each do |shift|
- next if shift.next_sym.nterm?
-
- @term_transitions << [shift, @items_to_state[shift.next_items]]
- end
-
- @term_transitions
+ @term_transitions ||= transitions.select {|shift, _| shift.next_sym.term? }
end
def transitions
- term_transitions + nterm_transitions
+ @transitions ||= shifts.map {|shift| [shift, @items_to_state[shift.next_items]] }
end
def selected_term_transitions
diff --git a/tool/lrama/lib/lrama/version.rb b/tool/lrama/lib/lrama/version.rb
index ccd593f344..ef840ce435 100644
--- a/tool/lrama/lib/lrama/version.rb
+++ b/tool/lrama/lib/lrama/version.rb
@@ -1,3 +1,3 @@
module Lrama
- VERSION = "0.6.5".freeze
+ VERSION = "0.6.9".freeze
end
diff --git a/tool/merger.rb b/tool/merger.rb
index d181a77f84..0d9957074f 100755
--- a/tool/merger.rb
+++ b/tool/merger.rb
@@ -57,11 +57,11 @@ class << Merger
yield if block_given?
STDERR.puts "\e[1;33m#{str} ([y]es|[a]bort|[r]etry#{'|[e]dit' if editfile})\e[0m"
case STDIN.gets
- when /\Aa/i then exit
+ when /\Aa/i then exit 1
when /\Ar/i then redo
when /\Ay/i then break
when /\Ae/i then system(ENV['EDITOR'], editfile)
- else exit
+ else exit 1
end
end
end
@@ -324,7 +324,10 @@ else
end
patch = resp.body.sub(/^diff --git a\/version\.h b\/version\.h\nindex .*\n--- a\/version\.h\n\+\+\+ b\/version\.h\n@@ .* @@\n(?:[-\+ ].*\n|\n)+/, '')
- message = "\n\n#{(patch[/^Subject: (.*)\n\ndiff --git/m, 1] || "Message not found for revision: #{git_rev}\n")}"
+ message = "#{(patch[/^Subject: (.*)\n---\n /m, 1] || "Message not found for revision: #{git_rev}\n")}"
+ message.gsub!(/\G(.*)\n( .*)/, "\\1\\2")
+ message = "\n\n#{message}"
+
puts '+ git apply'
IO.popen(['git', 'apply', '--3way'], 'wb') { |f| f.write(patch) }
else
diff --git a/tool/rdoc-srcdir b/tool/rdoc-srcdir
index 10c63caf9e..10c63caf9e 100644..100755
--- a/tool/rdoc-srcdir
+++ b/tool/rdoc-srcdir
diff --git a/tool/rubyspec_temp.rb b/tool/rubyspec_temp.rb
deleted file mode 100644
index 339bfce211..0000000000
--- a/tool/rubyspec_temp.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require "tmpdir"
-require "fileutils"
-
-if (tmpdir = Dir.mktmpdir("rubyspec_temp.")).size > 80
- # On macOS, the default TMPDIR is very long, inspite of UNIX socket
- # path length is limited.
- Dir.rmdir(tmpdir)
- tmpdir = Dir.mktmpdir("rubyspec_temp.", "/tmp")
-end
-# warn "tmpdir(#{tmpdir.size}) = #{tmpdir}"
-END {FileUtils.rm_rf(tmpdir)}
-
-ENV["TMPDIR"] = ENV["SPEC_TEMP_DIR"] = tmpdir
diff --git a/tool/test/testunit/test_assertion.rb b/tool/test/testunit/test_assertion.rb
index 709b495572..1e19c102b8 100644
--- a/tool/test/testunit/test_assertion.rb
+++ b/tool/test/testunit/test_assertion.rb
@@ -50,4 +50,17 @@ class TestAssertion < Test::Unit::TestCase
assert_pattern_list(pattern_list, actual, message)
end
end
+
+ def test_caller_bactrace_location
+ begin
+ line = __LINE__; assert_fail_for_backtrace_location
+ rescue Test::Unit::AssertionFailedError => e
+ end
+ location = Test::Unit::Runner.new.location(e)
+ assert_equal "#{__FILE__}:#{line}", location
+ end
+
+ def assert_fail_for_backtrace_location
+ assert false
+ end
end
diff --git a/tool/test_for_warn_bundled_gems/test.sh b/tool/test_for_warn_bundled_gems/test.sh
index 2404571daf..a14d5bcedc 100755
--- a/tool/test_for_warn_bundled_gems/test.sh
+++ b/tool/test_for_warn_bundled_gems/test.sh
@@ -32,6 +32,10 @@ echo "* Show warning with bootsnap"
ruby test_warn_bootsnap.rb
echo
+echo "* Show warning with bootsnap for gem with native extension"
+ruby test_warn_bootsnap_rubyarchdir_gem.rb
+echo
+
echo "* Show warning with zeitwerk"
ruby test_warn_zeitwerk.rb
echo
diff --git a/tool/test_for_warn_bundled_gems/test_warn_bootsnap_rubyarchdir_gem.rb b/tool/test_for_warn_bundled_gems/test_warn_bootsnap_rubyarchdir_gem.rb
new file mode 100644
index 0000000000..477933f6f2
--- /dev/null
+++ b/tool/test_for_warn_bundled_gems/test_warn_bootsnap_rubyarchdir_gem.rb
@@ -0,0 +1,11 @@
+require "bundler/inline"
+
+gemfile do
+ source "https://rubygems.org"
+ gem "bootsnap", require: false
+end
+
+require 'bootsnap'
+Bootsnap.setup(cache_dir: 'tmp/cache')
+
+require 'syslog'
diff --git a/tool/update-NEWS-refs.rb b/tool/update-NEWS-refs.rb
index 2b19f0fdaa..f48cac5ee1 100644
--- a/tool/update-NEWS-refs.rb
+++ b/tool/update-NEWS-refs.rb
@@ -13,8 +13,9 @@ if links.empty? || lines.last != ""
raise "NEWS.md must end with a sequence of links"
end
-labels = links.keys.select {|k| !(k.start_with?("Feature") || k.start_with?("Bug"))}
-new_src = lines.join("\n").gsub(/\[?\[((?:Feature|Bug)\s+#(\d+))\]\]?/) do
+trackers = ["Feature", "Bug", "Misc"]
+labels = links.keys.reject {|k| k.start_with?(*trackers)}
+new_src = lines.join("\n").gsub(/\[?\[(#{Regexp.union(trackers)}\s+#(\d+))\]\]?/) do
links[$1] ||= "https://bugs.ruby-lang.org/issues/#$2"
"[[#$1]]"
end.gsub(/\[\[#{Regexp.union(labels)}\]\]?/) do
@@ -22,7 +23,7 @@ end.gsub(/\[\[#{Regexp.union(labels)}\]\]?/) do
end.chomp + "\n\n"
label_width = links.max_by {|k, _| k.size}.first.size + 4
-redmine_links, non_redmine_links = links.partition {|k,| k =~ /\A(Feature|Bug)\s+#\d+\z/ }
+redmine_links, non_redmine_links = links.partition {|k,| k =~ /\A#{Regexp.union(trackers)}\s+#\d+\z/ }
(redmine_links.sort_by {|k,| k[/\d+/].to_i } + non_redmine_links.reverse).each do |k, v|
new_src << "[#{k}]:".ljust(label_width) << v << "\n"
diff --git a/universal_parser.c b/universal_parser.c
index 2055681889..c5e557ca30 100644
--- a/universal_parser.c
+++ b/universal_parser.c
@@ -59,7 +59,7 @@
#undef st_lookup
#define st_lookup rb_parser_st_lookup
-#define rb_encoding void
+#define rb_encoding const void
#undef xmalloc
#define xmalloc p->config->malloc
@@ -95,9 +95,6 @@
#undef rb_ary_new_from_args
#define rb_ary_new_from_args p->config->ary_new_from_args
#define rb_ary_unshift p->config->ary_unshift
-#undef RARRAY_LEN
-#define RARRAY_LEN p->config->array_len
-#define RARRAY_AREF p->config->array_aref
#define rb_make_temporary_id p->config->make_temporary_id
#define is_local_id p->config->is_local_id
@@ -122,8 +119,6 @@
#define rb_str_catf p->config->str_catf
#undef rb_str_cat_cstr
#define rb_str_cat_cstr p->config->str_cat_cstr
-#define rb_str_subseq p->config->str_subseq
-#define rb_str_new_frozen p->config->str_new_frozen
#define rb_str_modify p->config->str_modify
#define rb_str_set_len p->config->str_set_len
#define rb_str_cat p->config->str_cat
@@ -145,7 +140,6 @@
#define RSTRING_END p->config->rstring_end
#undef RSTRING_LEN
#define RSTRING_LEN p->config->rstring_len
-#define rb_filesystem_str_new_cstr p->config->filesystem_str_new_cstr
#define rb_obj_as_string p->config->obj_as_string
#undef INT2NUM
@@ -156,7 +150,6 @@
#define rb_io_write p->config->io_write
#define rb_io_flush p->config->io_flush
#define rb_io_puts p->config->io_puts
-#define rb_io_gets_internal p->config->io_gets_internal
#define rb_ractor_stdout p->config->debug_output_stdout
#define rb_ractor_stderr p->config->debug_output_stderr
@@ -175,14 +168,12 @@
#define rb_ascii8bit_encoding p->config->ascii8bit_encoding
#define rb_enc_codelen p->config->enc_codelen
#define rb_enc_mbcput p->config->enc_mbcput
+#define rb_enc_mbclen p->config->enc_mbclen
#define rb_enc_find_index p->config->enc_find_index
#define rb_enc_from_index p->config->enc_from_index
#define rb_enc_isspace p->config->enc_isspace
#define ENC_CODERANGE_7BIT p->config->enc_coderange_7bit
#define ENC_CODERANGE_UNKNOWN p->config->enc_coderange_unknown
-#define rb_enc_compatible p->config->enc_compatible
-#define rb_enc_from_encoding p->config->enc_from_encoding
-#define ENCODING_IS_ASCII8BIT p->config->encoding_is_ascii8bit
#define rb_usascii_encoding p->config->usascii_encoding
#define rb_local_defined p->config->local_defined
@@ -223,16 +214,12 @@
#define ruby_scan_digits p->config->scan_digits
#define strtod p->config->strtod
-#undef RBOOL
-#define RBOOL p->config->rbool
#undef RTEST
#define RTEST p->config->rtest
#undef NIL_P
#define NIL_P p->config->nil_p
#undef Qnil
#define Qnil p->config->qnil
-#undef Qtrue
-#define Qtrue p->config->qtrue
#undef Qfalse
#define Qfalse p->config->qfalse
#define rb_eArgError p->config->eArgError()
diff --git a/vm.c b/vm.c
index cf2bed84e4..7e39940017 100644
--- a/vm.c
+++ b/vm.c
@@ -1007,6 +1007,11 @@ 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;
}
@@ -1458,7 +1463,6 @@ rb_binding_add_dynavars(VALUE bindval, rb_binding_t *bind, int dyncount, const I
const rb_env_t *env;
rb_execution_context_t *ec = GET_EC();
const rb_iseq_t *base_iseq, *iseq;
- rb_ast_body_t ast;
rb_node_scope_t tmp_node;
if (dyncount < 0) return 0;
@@ -1476,17 +1480,14 @@ rb_binding_add_dynavars(VALUE bindval, rb_binding_t *bind, int dyncount, const I
tmp_node.nd_body = 0;
tmp_node.nd_args = 0;
- ast.root = RNODE(&tmp_node);
- ast.frozen_string_literal = -1;
- ast.coverage_enabled = -1;
- ast.script_lines = (rb_parser_ary_t *)INT2FIX(-1);
+ VALUE ast_value = rb_ruby_ast_new(RNODE(&tmp_node));
if (base_iseq) {
- iseq = rb_iseq_new(&ast, ISEQ_BODY(base_iseq)->location.label, path, realpath, base_iseq, ISEQ_TYPE_EVAL);
+ iseq = rb_iseq_new(ast_value, ISEQ_BODY(base_iseq)->location.label, path, realpath, base_iseq, ISEQ_TYPE_EVAL);
}
else {
VALUE tempstr = rb_fstring_lit("<temp>");
- iseq = rb_iseq_new_top(&ast, tempstr, tempstr, tempstr, NULL);
+ iseq = rb_iseq_new_top(ast_value, tempstr, tempstr, tempstr, NULL);
}
tmp_node.nd_tbl = 0; /* reset table */
ALLOCV_END(idtmp);
@@ -2859,7 +2860,7 @@ 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(0, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
+ 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,
@@ -3076,6 +3077,7 @@ ruby_vm_destruct(rb_vm_t *vm)
rb_vm_postponed_job_free();
rb_id_table_free(vm->constant_cache);
+ st_free_table(vm->unused_block_warning_table);
if (th) {
xfree(th->nt);
@@ -3301,7 +3303,6 @@ vm_default_params_setup(rb_vm_t *vm)
static void
vm_init2(rb_vm_t *vm)
{
- MEMZERO(vm, rb_vm_t, 1);
rb_vm_living_threads_init(vm);
vm->thread_report_on_exception = 1;
vm->src_encoding_index = -1;
@@ -4175,7 +4176,7 @@ Init_VM(void)
rb_vm_t *vm = ruby_current_vm_ptr;
rb_thread_t *th = GET_THREAD();
VALUE filename = rb_fstring_lit("<main>");
- const rb_iseq_t *iseq = rb_iseq_new(0, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
+ const rb_iseq_t *iseq = rb_iseq_new(Qnil, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
// Ractor setup
rb_ractor_main_setup(vm, th->ractor, th);
@@ -4237,15 +4238,14 @@ void
Init_BareVM(void)
{
/* VM bootstrap: phase 1 */
- rb_vm_t * vm = ruby_mimmalloc(sizeof(*vm));
- rb_thread_t * th = ruby_mimmalloc(sizeof(*th));
+ 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);
}
// setup the VM
- MEMZERO(th, rb_thread_t, 1);
vm_init2(vm);
rb_vm_postponed_job_queue_init(vm);
@@ -4256,6 +4256,12 @@ Init_BareVM(void)
vm->constant_cache = rb_id_table_create(0);
vm->unused_block_warning_table = st_init_numtable();
+ // TODO: remove before Ruby 3.4.0 release
+ const char *s = getenv("RUBY_TRY_UNUSED_BLOCK_WARNING_STRICT");
+ if (s && strcmp(s, "1") == 0) {
+ vm->unused_block_warning_strict = true;
+ }
+
// setup main thread
th->nt = ZALLOC(struct rb_native_thread);
th->vm = vm;
diff --git a/vm_callinfo.h b/vm_callinfo.h
index 21e0755aa8..71ab9fe3fa 100644
--- a/vm_callinfo.h
+++ b/vm_callinfo.h
@@ -240,21 +240,6 @@ vm_ci_new_runtime_(ID mid, unsigned int flag, unsigned int argc, const struct rb
#define VM_CALLINFO_NOT_UNDER_GC IMEMO_FL_USER0
-static inline bool
-vm_ci_markable(const struct rb_callinfo *ci)
-{
- if (! ci) {
- return false; /* or true? This is Qfalse... */
- }
- else if (vm_ci_packed_p(ci)) {
- return true;
- }
- else {
- VM_ASSERT(IMEMO_TYPE_P(ci, imemo_callinfo));
- return ! FL_ANY_RAW((VALUE)ci, VM_CALLINFO_NOT_UNDER_GC);
- }
-}
-
#define VM_CI_ON_STACK(mid_, flags_, argc_, kwarg_) \
(struct rb_callinfo) { \
.flags = T_IMEMO | \
@@ -575,7 +560,8 @@ struct rb_class_cc_entries {
int len;
const struct rb_callable_method_entry_struct *cme;
struct rb_class_cc_entries_entry {
- const struct rb_callinfo *ci;
+ unsigned int argc;
+ unsigned int flag;
const struct rb_callcache *cc;
} *entries;
};
diff --git a/vm_core.h b/vm_core.h
index 2400b02c7e..30e06c48ed 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -108,10 +108,10 @@ extern int ruby_assert_critical_section_entered;
#if USE_SHARED_GC
typedef struct gc_function_map {
- void *(*init)(void);
+ void *(*objspace_alloc)(void);
} rb_gc_function_map_t;
-#define rb_gc_functions (GET_VM()->gc_functions_map)
+#define rb_gc_functions (&GET_VM()->gc_functions_map)
#endif
/*
@@ -761,7 +761,7 @@ typedef struct rb_vm_struct {
struct rb_objspace *objspace;
#if USE_SHARED_GC
- rb_gc_function_map_t *gc_functions_map;
+ rb_gc_function_map_t gc_functions_map;
#endif
rb_at_exit_list *at_exit;
@@ -774,6 +774,7 @@ typedef struct rb_vm_struct {
struct rb_id_table *negative_cme_table;
st_table *overloaded_cme_table; // cme -> overloaded_cme
st_table *unused_block_warning_table;
+ bool unused_block_warning_strict;
// 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
@@ -1208,11 +1209,11 @@ typedef enum {
RUBY_SYMBOL_EXPORT_BEGIN
/* node -> iseq */
-rb_iseq_t *rb_iseq_new (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum rb_iseq_type);
-rb_iseq_t *rb_iseq_new_top (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent);
-rb_iseq_t *rb_iseq_new_main (const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt);
-rb_iseq_t *rb_iseq_new_eval (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth);
-rb_iseq_t *rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth,
+rb_iseq_t *rb_iseq_new (const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum rb_iseq_type);
+rb_iseq_t *rb_iseq_new_top (const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent);
+rb_iseq_t *rb_iseq_new_main (const VALUE ast_value, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt);
+rb_iseq_t *rb_iseq_new_eval (const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth);
+rb_iseq_t *rb_iseq_new_with_opt(const VALUE ast_value, 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*,
VALUE script_lines);
diff --git a/vm_eval.c b/vm_eval.c
index 25fa28d828..7eafb2d5f7 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -29,15 +29,6 @@ static VALUE rb_eUncaughtThrow;
static ID id_result, id_tag, id_value;
#define id_mesg idMesg
-typedef enum call_type {
- CALL_PUBLIC,
- CALL_FCALL,
- CALL_VCALL,
- CALL_PUBLIC_KW,
- CALL_FCALL_KW,
- CALL_TYPE_MAX
-} call_type;
-
static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope);
static VALUE vm_call0_body(rb_execution_context_t* ec, struct rb_calling_info *calling, const VALUE *argv);
@@ -403,71 +394,53 @@ NORETURN(static void uncallable_object(VALUE recv, ID mid));
static inline const rb_callable_method_entry_t *rb_search_method_entry(VALUE recv, ID mid);
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 const struct rb_callcache *
-cc_new(VALUE klass, ID mid, int argc, const rb_callable_method_entry_t *cme)
-{
- const struct rb_callcache *cc = NULL;
-
- RB_VM_LOCK_ENTER();
- {
- struct rb_class_cc_entries *ccs;
- struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
- VALUE ccs_data;
-
- if (rb_id_table_lookup(cc_tbl, mid, &ccs_data)) {
- // ok
- ccs = (struct rb_class_cc_entries *)ccs_data;
- }
- else {
- ccs = vm_ccs_create(klass, cc_tbl, mid, cme);
- }
-
- for (int i=0; i<ccs->len; i++) {
- cc = ccs->entries[i].cc;
- if (vm_cc_cme(cc) == cme) {
- break;
- }
- cc = NULL;
- }
-
- if (cc == NULL) {
- const struct rb_callinfo *ci = vm_ci_new(mid, 0, argc, NULL); // TODO: proper ci
- cc = vm_cc_new(klass, cme, vm_call_general, cc_type_normal);
- METHOD_ENTRY_CACHED_SET((struct rb_callable_method_entry_struct *)cme);
- vm_ccs_push(klass, ccs, ci, cc);
- }
- }
- RB_VM_LOCK_LEAVE();
-
- return cc;
-}
-
static VALUE
gccct_hash(VALUE klass, ID mid)
{
return (klass >> 3) ^ (VALUE)mid;
}
-NOINLINE(static const struct rb_callcache *gccct_method_search_slowpath(rb_vm_t *vm, VALUE klass, ID mid, int argc, unsigned int index));
+NOINLINE(static const struct rb_callcache *gccct_method_search_slowpath(rb_vm_t *vm, VALUE klass, unsigned int index, const struct rb_callinfo * ci));
static const struct rb_callcache *
-gccct_method_search_slowpath(rb_vm_t *vm, VALUE klass, ID mid, int argc, unsigned int index)
+gccct_method_search_slowpath(rb_vm_t *vm, VALUE klass, unsigned int index, const struct rb_callinfo *ci)
{
- const rb_callable_method_entry_t *cme = rb_callable_method_entry(klass, mid);
- const struct rb_callcache *cc;
+ struct rb_call_data cd = {
+ .ci = ci,
+ .cc = NULL
+ };
- if (cme != NULL) {
- cc = cc_new(klass, mid, argc, cme);
- }
- else {
- cc = NULL;
- }
+ vm_search_method_slowpath0(vm->self, &cd, klass);
+
+ return vm->global_cc_cache_table[index] = cd.cc;
+}
+
+static void
+scope_to_ci(call_type scope, ID mid, int argc, struct rb_callinfo *ci)
+{
+ int flags = 0;
- return vm->global_cc_cache_table[index] = cc;
+ switch(scope) {
+ case CALL_PUBLIC:
+ break;
+ case CALL_FCALL:
+ flags |= VM_CALL_FCALL;
+ break;
+ case CALL_VCALL:
+ flags |= VM_CALL_VCALL;
+ break;
+ case CALL_PUBLIC_KW:
+ flags |= VM_CALL_KWARG;
+ break;
+ case CALL_FCALL_KW:
+ flags |= (VM_CALL_KWARG | VM_CALL_FCALL);
+ break;
+ }
+ *ci = VM_CI_ON_STACK(mid, flags, argc, NULL);
}
static inline const struct rb_callcache *
-gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, int argc)
+gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct rb_callinfo *ci)
{
VALUE klass;
@@ -502,7 +475,7 @@ gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, int argc)
}
RB_DEBUG_COUNTER_INC(gccct_miss);
- return gccct_method_search_slowpath(vm, klass, mid, argc, index);
+ return gccct_method_search_slowpath(vm, klass, index, ci);
}
/**
@@ -543,7 +516,10 @@ rb_call0(rb_execution_context_t *ec,
break;
}
- const struct rb_callcache *cc = gccct_method_search(ec, recv, mid, argc);
+ struct rb_callinfo ci;
+ scope_to_ci(scope, mid, argc, &ci);
+
+ const struct rb_callcache *cc = gccct_method_search(ec, recv, mid, &ci);
if (scope == CALL_PUBLIC) {
RB_DEBUG_COUNTER_INC(call0_public);
@@ -1060,7 +1036,11 @@ static inline VALUE
rb_funcallv_scope(VALUE recv, ID mid, int argc, const VALUE *argv, call_type scope)
{
rb_execution_context_t *ec = GET_EC();
- const struct rb_callcache *cc = gccct_method_search(ec, recv, mid, argc);
+
+ struct rb_callinfo ci;
+ scope_to_ci(scope, mid, argc, &ci);
+
+ const struct rb_callcache *cc = gccct_method_search(ec, recv, mid, &ci);
VALUE self = ec->cfp->self;
if (LIKELY(cc) &&
@@ -1773,6 +1753,7 @@ eval_make_iseq(VALUE src, VALUE fname, int line,
const VALUE parser = rb_parser_new();
const rb_iseq_t *const parent = vm_block_iseq(base_block);
rb_iseq_t *iseq = NULL;
+ VALUE ast_value;
rb_ast_t *ast;
int isolated_depth = 0;
@@ -1810,10 +1791,13 @@ eval_make_iseq(VALUE src, VALUE fname, int line,
rb_parser_set_context(parser, parent, FALSE);
if (ruby_vm_keep_script_lines) rb_parser_set_script_lines(parser);
- ast = rb_parser_compile_string_path(parser, fname, src, line);
+ ast_value = rb_parser_compile_string_path(parser, fname, src, line);
+
+ ast = rb_ruby_ast_data_get(ast_value);
+
if (ast->body.root) {
ast->body.coverage_enabled = coverage_enabled;
- iseq = rb_iseq_new_eval(&ast->body,
+ iseq = rb_iseq_new_eval(ast_value,
ISEQ_BODY(parent)->location.label,
fname, Qnil, line,
parent, isolated_depth);
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 84ef212053..a1893b1ba2 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -2006,9 +2006,6 @@ vm_ccs_push(VALUE klass, struct rb_class_cc_entries *ccs, const struct rb_callin
if (! vm_cc_markable(cc)) {
return;
}
- else if (! vm_ci_markable(ci)) {
- return;
- }
if (UNLIKELY(ccs->len == ccs->capa)) {
if (ccs->capa == 0) {
@@ -2023,7 +2020,8 @@ vm_ccs_push(VALUE klass, struct rb_class_cc_entries *ccs, const struct rb_callin
VM_ASSERT(ccs->len < ccs->capa);
const int pos = ccs->len++;
- RB_OBJ_WRITE(klass, &ccs->entries[pos].ci, ci);
+ 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);
if (RB_DEBUG_COUNTER_SETMAX(ccs_maxlen, ccs->len)) {
@@ -2038,7 +2036,9 @@ rb_vm_ccs_dump(struct rb_class_cc_entries *ccs)
{
ruby_debug_printf("ccs:%p (%d,%d)\n", (void *)ccs, ccs->len, ccs->capa);
for (int i=0; i<ccs->len; i++) {
- vm_ci_dump(ccs->entries[i].ci);
+ ruby_debug_printf("CCS CI ID:flag:%x argc:%u\n",
+ ccs->entries[i].flag,
+ ccs->entries[i].argc);
rp(ccs->entries[i].cc);
}
}
@@ -2050,11 +2050,8 @@ vm_ccs_verify(struct rb_class_cc_entries *ccs, ID mid, VALUE klass)
VM_ASSERT(ccs->len <= ccs->capa);
for (int i=0; i<ccs->len; i++) {
- const struct rb_callinfo *ci = ccs->entries[i].ci;
const struct rb_callcache *cc = ccs->entries[i].cc;
- VM_ASSERT(vm_ci_p(ci));
- VM_ASSERT(vm_ci_mid(ci) == mid);
VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
VM_ASSERT(vm_cc_class_check(cc, klass));
VM_ASSERT(vm_cc_check_cme(cc, ccs->cme));
@@ -2076,6 +2073,8 @@ vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci)
VALUE ccs_data;
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;
const int ccs_len = ccs->len;
@@ -2088,14 +2087,20 @@ vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci)
else {
VM_ASSERT(vm_ccs_verify(ccs, mid, klass));
+ // We already know the method id is correct because we had
+ // to look up the ccs_data by method id. All we need to
+ // compare is argc and flag
+ unsigned int argc = vm_ci_argc(ci);
+ unsigned int flag = vm_ci_flag(ci);
+
for (int i=0; i<ccs_len; i++) {
- const struct rb_callinfo *ccs_ci = ccs->entries[i].ci;
+ unsigned int ccs_ci_argc = ccs->entries[i].argc;
+ unsigned int ccs_ci_flag = ccs->entries[i].flag;
const struct rb_callcache *ccs_cc = ccs->entries[i].cc;
- VM_ASSERT(vm_ci_p(ccs_ci));
VM_ASSERT(IMEMO_TYPE_P(ccs_cc, imemo_callcache));
- if (ccs_ci == ci) { // TODO: equality
+ if (ccs_ci_argc == argc && ccs_ci_flag == flag) {
RB_DEBUG_COUNTER_INC(cc_found_in_ccs);
VM_ASSERT(vm_cc_cme(ccs_cc)->called_id == mid);
@@ -2416,13 +2421,13 @@ opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd)
#undef EQ_UNREDEFINED_P
-static inline const struct rb_callcache *gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, int argc); // vm_eval.c
+static inline const struct rb_callcache *gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct rb_callinfo *ci); // vm_eval.c
NOINLINE(static VALUE opt_equality_by_mid_slowpath(VALUE recv, VALUE obj, ID mid));
static VALUE
opt_equality_by_mid_slowpath(VALUE recv, VALUE obj, ID mid)
{
- const struct rb_callcache *cc = gccct_method_search(GET_EC(), recv, mid, 1);
+ const struct rb_callcache *cc = gccct_method_search(GET_EC(), recv, mid, &VM_CI_ON_STACK(mid, 0, 1, NULL));
if (cc && check_cfunc(vm_cc_cme(cc), rb_obj_equal)) {
return RBOOL(recv == obj);
@@ -2973,6 +2978,7 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
{
rb_vm_t *vm = GET_VM();
st_table *dup_check_table = vm->unused_block_warning_table;
+ st_data_t key;
union {
VALUE v;
@@ -2984,14 +2990,17 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
};
// relax check
- st_data_t key = (st_data_t)cme->def->original_id;
+ if (!vm->unused_block_warning_strict) {
+ key = (st_data_t)cme->def->original_id;
- if (st_lookup(dup_check_table, key, NULL)) {
- return;
+ if (st_lookup(dup_check_table, key, NULL)) {
+ return;
+ }
}
// strict check
// make unique key from pc and me->def pointer
+ key = 0;
for (int i=0; i<SIZEOF_VALUE; i++) {
// fprintf(stderr, "k1:%3d k2:%3d\n", k1.b[i], k2.b[SIZEOF_VALUE-1-i]);
key |= (st_data_t)(k1.b[i] ^ k2.b[SIZEOF_VALUE-1-i]) << (8 * i);
@@ -3027,7 +3036,6 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
{
const struct rb_callinfo *ci = calling->cd->ci;
const struct rb_callcache *cc = calling->cc;
- bool cacheable_ci = vm_ci_markable(ci);
if (UNLIKELY(!ISEQ_BODY(iseq)->param.flags.use_block &&
calling->block_handler != VM_BLOCK_HANDLER_NONE &&
@@ -3048,7 +3056,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
VM_ASSERT(ci == calling->cd->ci);
VM_ASSERT(cc == calling->cc);
- if (cacheable_ci && vm_call_iseq_optimizable_p(ci, 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))) {
VM_ASSERT(iseq->body->builtin_attrs & BUILTIN_ATTR_LEAF);
@@ -3078,12 +3086,12 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_TAILCALL))) {
CC_SET_FASTPATH(cc, vm_call_iseq_setup_normal_opt_start,
!IS_ARGS_SPLAT(ci) && !IS_ARGS_KEYWORD(ci) &&
- cacheable_ci && vm_call_cacheable(ci, cc));
+ vm_call_cacheable(ci, cc));
}
else {
CC_SET_FASTPATH(cc, vm_call_iseq_setup_tailcall_opt_start,
!IS_ARGS_SPLAT(ci) && !IS_ARGS_KEYWORD(ci) &&
- cacheable_ci && vm_call_cacheable(ci, cc));
+ vm_call_cacheable(ci, cc));
}
/* initialize opt vars for self-references */
@@ -3111,7 +3119,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
args_setup_kw_parameters(ec, iseq, ci_kws, ci_kw_len, ci_keywords, klocals);
CC_SET_FASTPATH(cc, vm_call_iseq_setup_kwparm_kwarg,
- cacheable_ci && vm_call_cacheable(ci, cc));
+ vm_call_cacheable(ci, cc));
return 0;
}
@@ -3124,7 +3132,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
if (klocals[kw_param->num] == INT2FIX(0)) {
/* copy from default_values */
CC_SET_FASTPATH(cc, vm_call_iseq_setup_kwparm_nokwarg,
- cacheable_ci && vm_call_cacheable(ci, cc));
+ vm_call_cacheable(ci, cc));
}
return 0;
diff --git a/vm_insnhelper.h b/vm_insnhelper.h
index 286bc1f671..926700b90a 100644
--- a/vm_insnhelper.h
+++ b/vm_insnhelper.h
@@ -58,6 +58,14 @@ RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
VM_REG_CFP = ec->cfp; \
} while (0)
+typedef enum call_type {
+ CALL_PUBLIC,
+ CALL_FCALL,
+ CALL_VCALL,
+ CALL_PUBLIC_KW,
+ CALL_FCALL_KW
+} call_type;
+
#if VM_COLLECT_USAGE_DETAILS
enum vm_regan_regtype {
VM_REGAN_PC = 0,
diff --git a/vm_method.c b/vm_method.c
index 5ca302a86a..3cacc010b8 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -31,7 +31,6 @@ vm_ccs_dump_i(ID mid, VALUE val, void *data)
rp(ccs->cme);
for (int i=0; i<ccs->len; i++) {
- fprintf(stderr, " | [%d]\t", i); vm_ci_dump(ccs->entries[i].ci);
rp_m( " | \t", ccs->entries[i].cc);
}
@@ -428,7 +427,6 @@ rb_vm_ci_lookup(ID mid, unsigned int flag, unsigned int argc, const struct rb_ca
RB_VM_LOCK_LEAVE();
VM_ASSERT(ci);
- VM_ASSERT(vm_ci_markable(ci));
return ci;
}
@@ -1016,7 +1014,6 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil
old_def->type != VM_METHOD_TYPE_ALIAS) {
const rb_iseq_t *iseq = 0;
- rb_warning("method redefined; discarding old %"PRIsVALUE, rb_id2str(mid));
switch (old_def->type) {
case VM_METHOD_TYPE_ISEQ:
iseq = def_iseq_ptr(old_def);
@@ -1028,10 +1025,16 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil
break;
}
if (iseq) {
- rb_compile_warning(RSTRING_PTR(rb_iseq_path(iseq)),
- ISEQ_BODY(iseq)->location.first_lineno,
- "previous definition of %"PRIsVALUE" was here",
- rb_id2str(old_def->original_id));
+ rb_warning(
+ "method redefined; discarding old %"PRIsVALUE"\n%s:%d: warning: previous definition of %"PRIsVALUE" was here",
+ rb_id2str(mid),
+ RSTRING_PTR(rb_iseq_path(iseq)),
+ ISEQ_BODY(iseq)->location.first_lineno,
+ rb_id2str(old_def->original_id)
+ );
+ }
+ else {
+ rb_warning("method redefined; discarding old %"PRIsVALUE, rb_id2str(mid));
}
}
}
diff --git a/weakmap.c b/weakmap.c
index a8e9fe2f8a..8939056811 100644
--- a/weakmap.c
+++ b/weakmap.c
@@ -586,7 +586,7 @@ wmap_size(VALUE self)
* the key and the object as the value. This means that the key is of the type
* `VALUE *` while the value is of the type `VALUE`.
*
- * The object is not not directly stored as keys in the table because
+ * The object is not directly stored as keys in the table because
* `rb_gc_mark_weak` requires a pointer to the memory location to overwrite
* when the object is reclaimed. Using a pointer into the ST table entry is not
* safe because the pointer can change when the ST table is resized.
@@ -985,7 +985,7 @@ wkmap_inspect(VALUE self)
*
* Keys in the map are compared by identity.
*
- * m = ObjectSpace::WeekMap.new
+ * m = ObjectSpace::WeakMap.new
* key1 = "foo"
* val1 = Object.new
* m[key1] = val1
@@ -1041,13 +1041,13 @@ wkmap_inspect(VALUE self)
*
* val = nil
* GC.start
- * # There is no more references to `val`, yet the pair isn't
+ * # There are no more references to `val`, yet the pair isn't
* # garbage-collected.
* map["name"] #=> 2023-12-07 00:00:00 +0200
*
* key = nil
* GC.start
- * # There is no more references to `key`, key and value are
+ * # There are no more references to `key`, key and value are
* # garbage-collected.
* map["name"] #=> nil
*
diff --git a/yjit.c b/yjit.c
index ffd180429e..d40ac81fb5 100644
--- a/yjit.c
+++ b/yjit.c
@@ -629,6 +629,12 @@ 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)
{
@@ -1041,7 +1047,6 @@ rb_yjit_multi_ractor_p(void)
void
rb_assert_iseq_handle(VALUE handle)
{
- RUBY_ASSERT_ALWAYS(rb_objspace_markable_object_p(handle));
RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_iseq));
}
@@ -1158,20 +1163,14 @@ yjit_root_memsize(const void *ptr)
return 0; // TODO: more accurate accounting
}
-// GC callback during compaction
-static void
-yjit_root_update_references(void *ptr)
-{
- // Do nothing since we use rb_gc_mark(), which pins.
-}
-
void rb_yjit_root_mark(void *ptr); // in Rust
+void rb_yjit_root_update_references(void *ptr); // in Rust
// Custom type for interacting with the GC
// TODO: make this write barrier protected
static const rb_data_type_t yjit_root_type = {
"yjit_root",
- {rb_yjit_root_mark, yjit_root_free, yjit_root_memsize, yjit_root_update_references},
+ {rb_yjit_root_mark, yjit_root_free, yjit_root_memsize, rb_yjit_root_update_references},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
diff --git a/yjit.h b/yjit.h
index dde9f750aa..5d1de2df90 100644
--- a/yjit.h
+++ b/yjit.h
@@ -40,14 +40,15 @@ void rb_yjit_init(bool yjit_enabled);
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);
-void rb_yjit_iseq_update_references(void *payload);
-void rb_yjit_iseq_free(void *payload);
+void rb_yjit_iseq_update_references(const rb_iseq_t *iseq);
+void rb_yjit_iseq_free(const rb_iseq_t *iseq);
void rb_yjit_before_ractor_spawn(void);
void rb_yjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx);
void rb_yjit_tracing_invalidate_all(void);
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);
#else
// !USE_YJIT
@@ -64,13 +65,14 @@ 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) {}
static inline void rb_yjit_iseq_mark(void *payload) {}
-static inline void rb_yjit_iseq_update_references(void *payload) {}
-static inline void rb_yjit_iseq_free(void *payload) {}
+static inline void rb_yjit_iseq_update_references(const rb_iseq_t *iseq) {}
+static inline void rb_yjit_iseq_free(const rb_iseq_t *iseq) {}
static inline void rb_yjit_before_ractor_spawn(void) {}
static inline void rb_yjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx) {}
static inline void rb_yjit_tracing_invalidate_all(void) {}
static inline void rb_yjit_lazy_push_frame(const VALUE *pc) {}
static inline void rb_yjit_invalidate_no_singleton_class(VALUE klass) {}
+static inline void rb_yjit_invalidate_ep_is_bp(const rb_iseq_t *iseq) {}
#endif // #if USE_YJIT
diff --git a/yjit.rb b/yjit.rb
index eedd00c358..6612d8bd82 100644
--- a/yjit.rb
+++ b/yjit.rb
@@ -201,13 +201,27 @@ module RubyVM::YJIT
# If a method or proc is passed in, get its iseq
iseq = RubyVM::InstructionSequence.of(iseq)
- if self.enabled?
- # Produce the disassembly string
- # Include the YARV iseq disasm in the string for additional context
- iseq.disasm + "\n" + Primitive.rb_yjit_disasm_iseq(iseq)
- else
- iseq.disasm
+ 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)"
+ )
+ return nil
end
+
+ disasm_str = Primitive.rb_yjit_disasm_iseq(iseq)
+
+ 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"
+ )
+ return nil
+ end
+
+ # Produce the disassembly string
+ # Include the YARV iseq disasm in the string for additional context
+ iseq.disasm + "\n" + disasm_str
end
# Produce a list of instructions compiled by YJIT for an iseq
diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs
index c58df7c377..a7473c1bf6 100644
--- a/yjit/bindgen/src/main.rs
+++ b/yjit/bindgen/src/main.rs
@@ -174,6 +174,7 @@ fn main() {
.allowlist_var("rb_cThread")
.allowlist_var("rb_cArray")
.allowlist_var("rb_cHash")
+ .allowlist_var("rb_cClass")
// From include/ruby/internal/fl_type.h
.allowlist_type("ruby_fl_type")
@@ -298,6 +299,7 @@ fn main() {
.allowlist_type("ruby_tag_type")
.allowlist_type("ruby_vm_throw_flags")
.allowlist_type("vm_check_match_type")
+ .allowlist_type("rb_iseq_type")
// From yjit.c
.allowlist_function("rb_iseq_(get|set)_yjit_payload")
@@ -378,6 +380,7 @@ fn main() {
// From internal/object.h
.allowlist_function("rb_class_allocate_instance")
+ .allowlist_function("rb_obj_equal")
// From gc.h and internal/gc.h
.allowlist_function("rb_obj_info")
@@ -415,6 +418,7 @@ fn main() {
.allowlist_function("rb_get_iseq_body_parent_iseq")
.allowlist_function("rb_get_iseq_body_iseq_encoded")
.allowlist_function("rb_get_iseq_body_stack_max")
+ .allowlist_function("rb_get_iseq_body_type")
.allowlist_function("rb_get_iseq_flags_has_lead")
.allowlist_function("rb_get_iseq_flags_has_opt")
.allowlist_function("rb_get_iseq_flags_has_kw")
diff --git a/yjit/src/asm/arm64/mod.rs b/yjit/src/asm/arm64/mod.rs
index 8365c34955..a94d435b7c 100644
--- a/yjit/src/asm/arm64/mod.rs
+++ b/yjit/src/asm/arm64/mod.rs
@@ -215,6 +215,9 @@ pub const fn bcond_offset_fits_bits(offset: i64) -> bool {
imm_fits_bits(offset, 19)
}
+/// CBZ and CBNZ also have a limit of 19 bits for the branch offset.
+pub use bcond_offset_fits_bits as cmp_branch_offset_fits_bits;
+
/// B.cond - branch to target if condition is true
pub fn bcond(cb: &mut CodeBlock, cond: u8, offset: InstructionOffset) {
assert!(bcond_offset_fits_bits(offset.into()), "The offset must be 19 bits or less.");
@@ -1096,6 +1099,48 @@ pub fn tst(cb: &mut CodeBlock, rn: A64Opnd, rm: A64Opnd) {
cb.write_bytes(&bytes);
}
+/// CBZ - branch if a register is zero
+pub fn cbz(cb: &mut CodeBlock, rt: A64Opnd, offset: InstructionOffset) {
+ assert!(imm_fits_bits(offset.into(), 19), "jump offset for cbz must fit in 19 bits");
+ let bytes: [u8; 4] = if let A64Opnd::Reg(rt) = rt {
+ cbz_cbnz(rt.num_bits, false, offset, rt.reg_no)
+ } else {
+ panic!("Invalid operand combination to cbz instruction.")
+ };
+
+ cb.write_bytes(&bytes);
+}
+
+/// CBNZ - branch if a register is non-zero
+pub fn cbnz(cb: &mut CodeBlock, rt: A64Opnd, offset: InstructionOffset) {
+ assert!(imm_fits_bits(offset.into(), 19), "jump offset for cbz must fit in 19 bits");
+ let bytes: [u8; 4] = if let A64Opnd::Reg(rt) = rt {
+ cbz_cbnz(rt.num_bits, true, offset, rt.reg_no)
+ } else {
+ panic!("Invalid operand combination to cbnz instruction.")
+ };
+
+ cb.write_bytes(&bytes);
+}
+
+/// Encode Compare and Branch on Zero (CBZ) with `op=0` or Compare and Branch on Nonzero (CBNZ)
+/// with `op=1`.
+///
+/// <https://developer.arm.com/documentation/ddi0602/2024-03/Base-Instructions/CBZ--Compare-and-Branch-on-Zero->
+///
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+/// | 31 30 29 28 | 27 26 25 24 | 23 22 21 20 | 19 18 17 16 | 15 14 13 12 | 11 10 09 08 | 07 06 05 04 | 03 02 01 00 |
+/// | sf 0 1 1 0 1 0 op |
+/// | imm19........................................................... Rt.............. |
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+fn cbz_cbnz(num_bits: u8, op: bool, offset: InstructionOffset, rt: u8) -> [u8; 4] {
+ ((Sf::from(num_bits) as u32) << 31 |
+ 0b11010 << 25 |
+ u32::from(op) << 24 |
+ truncate_imm::<_, 19>(offset) << 5 |
+ rt as u32).to_le_bytes()
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -1271,6 +1316,24 @@ mod tests {
}
#[test]
+ fn test_cbz() {
+ let offset = InstructionOffset::from_insns(-1);
+ check_bytes("e0ffffb4e0ffff34", |cb| {
+ cbz(cb, X0, offset);
+ cbz(cb, W0, offset);
+ });
+ }
+
+ #[test]
+ fn test_cbnz() {
+ let offset = InstructionOffset::from_insns(2);
+ check_bytes("540000b554000035", |cb| {
+ cbnz(cb, X20, offset);
+ cbnz(cb, W20, offset);
+ });
+ }
+
+ #[test]
fn test_brk_none() {
check_bytes("000020d4", |cb| brk(cb, A64Opnd::None));
}
diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs
index a62ea45e7e..3bf949ba7d 100644
--- a/yjit/src/backend/arm64/mod.rs
+++ b/yjit/src/backend/arm64/mod.rs
@@ -459,7 +459,34 @@ impl Assembler
}
asm.push_insn(insn);
- },
+ }
+ // Lower to Joz and Jonz for generating CBZ/CBNZ for compare-with-0-and-branch.
+ ref insn @ Insn::Cmp { ref left, right: ref right @ (Opnd::UImm(0) | Opnd::Imm(0)) } |
+ ref insn @ Insn::Test { ref left, right: ref right @ (Opnd::InsnOut { .. } | Opnd::Reg(_)) } if {
+ let same_opnd_if_test = if let Insn::Test { .. } = insn {
+ left == right
+ } else {
+ true
+ };
+
+ same_opnd_if_test && if let Some(
+ Insn::Jz(target) | Insn::Je(target) | Insn::Jnz(target) | Insn::Jne(target)
+ ) = iterator.peek() {
+ matches!(target, Target::SideExit { .. })
+ } else {
+ false
+ }
+ } => {
+ let reg = split_load_operand(asm, *left);
+ match iterator.peek() {
+ Some(Insn::Jz(target) | Insn::Je(target)) => asm.push_insn(Insn::Joz(reg, *target)),
+ Some(Insn::Jnz(target) | Insn::Jne(target)) => asm.push_insn(Insn::Jonz(reg, *target)),
+ _ => ()
+ }
+
+ iterator.map_insn_index(asm);
+ iterator.next_unmapped(); // Pop merged jump instruction
+ }
Insn::CCall { opnds, fptr, .. } => {
assert!(opnds.len() <= C_ARG_OPNDS.len());
@@ -812,6 +839,45 @@ impl Assembler
};
}
+ /// Emit a CBZ or CBNZ which branches when a register is zero or non-zero
+ fn emit_cmp_zero_jump(cb: &mut CodeBlock, reg: A64Opnd, branch_if_zero: bool, target: Target) {
+ if let Target::SideExitPtr(dst_ptr) = target {
+ let dst_addr = dst_ptr.as_offset();
+ let src_addr = cb.get_write_ptr().as_offset();
+
+ if cmp_branch_offset_fits_bits((dst_addr - src_addr) / 4) {
+ // If the offset fits in one instruction, generate cbz or cbnz
+ let bytes = (dst_addr - src_addr) as i32;
+ if branch_if_zero {
+ cbz(cb, reg, InstructionOffset::from_bytes(bytes));
+ } else {
+ cbnz(cb, reg, InstructionOffset::from_bytes(bytes));
+ }
+ } else {
+ // Otherwise, we load the address into a register and
+ // use the branch register instruction. Note that because
+ // side exits should always be close, this form should be
+ // rare or impossible to see.
+ let dst_addr = dst_ptr.raw_addr(cb) as u64;
+ let load_insns: i32 = emit_load_size(dst_addr).into();
+
+ // Write out the inverse condition so that if
+ // it doesn't match it will skip over the
+ // instructions used for branching.
+ if branch_if_zero {
+ cbnz(cb, reg, InstructionOffset::from_insns(load_insns + 2));
+ } else {
+ cbz(cb, reg, InstructionOffset::from_insns(load_insns + 2));
+ }
+ emit_load_value(cb, Assembler::SCRATCH0, dst_addr);
+ br(cb, Assembler::SCRATCH0);
+
+ }
+ } else {
+ unreachable!("We should only generate Joz/Jonz with side-exit targets");
+ }
+ }
+
/// Emit a push instruction for the given operand by adding to the stack
/// pointer and then storing the given value.
fn emit_push(cb: &mut CodeBlock, opnd: A64Opnd) {
@@ -1172,6 +1238,12 @@ impl Assembler
Insn::Jo(target) => {
emit_conditional_jump::<{Condition::VS}>(cb, compile_side_exit(*target, self, ocb)?);
},
+ Insn::Joz(opnd, target) => {
+ emit_cmp_zero_jump(cb, opnd.into(), true, compile_side_exit(*target, self, ocb)?);
+ },
+ Insn::Jonz(opnd, target) => {
+ emit_cmp_zero_jump(cb, opnd.into(), false, compile_side_exit(*target, self, ocb)?);
+ },
Insn::IncrCounter { mem, value } => {
let label = cb.new_label("incr_counter_loop".to_string());
cb.write_label(label);
diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs
index 1adff22f74..edc0eaf390 100644
--- a/yjit/src/backend/ir.rs
+++ b/yjit/src/backend/ir.rs
@@ -452,6 +452,12 @@ pub enum Insn {
/// Jump if zero
Jz(Target),
+ /// Jump if operand is zero (only used during lowering at the moment)
+ Joz(Opnd, Target),
+
+ /// Jump if operand is non-zero (only used during lowering at the moment)
+ Jonz(Opnd, Target),
+
// Add a label into the IR at the point that this instruction is added.
Label(Target),
@@ -547,6 +553,9 @@ impl Insn {
Insn::Jo(target) |
Insn::Jz(target) |
Insn::Label(target) |
+ Insn::JoMul(target) |
+ Insn::Joz(_, target) |
+ Insn::Jonz(_, target) |
Insn::LeaJumpTarget { target, .. } => {
Some(target)
}
@@ -595,6 +604,8 @@ impl Insn {
Insn::Jo(_) => "Jo",
Insn::JoMul(_) => "JoMul",
Insn::Jz(_) => "Jz",
+ Insn::Joz(..) => "Joz",
+ Insn::Jonz(..) => "Jonz",
Insn::Label(_) => "Label",
Insn::LeaJumpTarget { .. } => "LeaJumpTarget",
Insn::Lea { .. } => "Lea",
@@ -755,6 +766,7 @@ impl<'a> Iterator for InsnOpndIterator<'a> {
Insn::LeaJumpTarget { .. } |
Insn::PadInvalPatch |
Insn::PosMarker(_) => None,
+
Insn::CPopInto(opnd) |
Insn::CPush(opnd) |
Insn::CRet(opnd) |
@@ -763,6 +775,8 @@ impl<'a> Iterator for InsnOpndIterator<'a> {
Insn::LiveReg { opnd, .. } |
Insn::Load { opnd, .. } |
Insn::LoadSExt { opnd, .. } |
+ Insn::Joz(opnd, _) |
+ Insn::Jonz(opnd, _) |
Insn::Not { opnd, .. } => {
match self.idx {
0 => {
@@ -857,6 +871,7 @@ impl<'a> InsnOpndMutIterator<'a> {
Insn::LeaJumpTarget { .. } |
Insn::PadInvalPatch |
Insn::PosMarker(_) => None,
+
Insn::CPopInto(opnd) |
Insn::CPush(opnd) |
Insn::CRet(opnd) |
@@ -865,6 +880,8 @@ impl<'a> InsnOpndMutIterator<'a> {
Insn::LiveReg { opnd, .. } |
Insn::Load { opnd, .. } |
Insn::LoadSExt { opnd, .. } |
+ Insn::Joz(opnd, _) |
+ Insn::Jonz(opnd, _) |
Insn::Not { opnd, .. } => {
match self.idx {
0 => {
diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs
index d52ed265bd..4ca5e9be9c 100644
--- a/yjit/src/backend/x86_64/mod.rs
+++ b/yjit/src/backend/x86_64/mod.rs
@@ -796,6 +796,8 @@ impl Assembler
}
}
+ Insn::Joz(..) | Insn::Jonz(..) => unreachable!("Joz/Jonz should be unused for now"),
+
// Atomically increment a counter at a given memory location
Insn::IncrCounter { mem, value } => {
assert!(matches!(mem, Opnd::Mem(_)));
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index 8ab5e0e230..072d96f1b0 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -46,7 +46,7 @@ type InsnGenFn = fn(
/// Represents a [core::Block] while we build it.
pub struct JITState {
/// Instruction sequence for the compiling block
- iseq: IseqPtr,
+ pub iseq: IseqPtr,
/// The iseq index of the first instruction in the block
starting_insn_idx: IseqIdx,
@@ -101,6 +101,9 @@ pub struct JITState {
/// A list of classes that are not supposed to have a singleton class.
pub no_singleton_class_assumptions: Vec<VALUE>,
+ /// When true, the block is valid only when base pointer is equal to environment pointer.
+ pub no_ep_escape: bool,
+
/// When true, the block is valid only when there is a total of one ractor running
pub block_assumes_single_ractor: bool,
@@ -130,6 +133,7 @@ impl JITState {
bop_assumptions: vec![],
stable_constant_names_assumption: None,
no_singleton_class_assumptions: vec![],
+ no_ep_escape: false,
block_assumes_single_ractor: false,
perf_map: Rc::default(),
perf_stack: vec![],
@@ -171,6 +175,23 @@ impl JITState {
unsafe { *(self.pc.offset(arg_idx + 1)) }
}
+ /// Return true if the current ISEQ could escape an environment.
+ ///
+ /// As of vm_push_frame(), EP is always equal to BP. However, after pushing
+ /// a frame, some ISEQ setups call vm_bind_update_env(), which redirects EP.
+ /// Also, some method calls escape the environment to the heap.
+ fn escapes_ep(&self) -> bool {
+ match unsafe { get_iseq_body_type(self.iseq) } {
+ // <main> frame is always associated to TOPLEVEL_BINDING.
+ ISEQ_TYPE_MAIN |
+ // Kernel#eval uses a heap EP when a Binding argument is not nil.
+ ISEQ_TYPE_EVAL => true,
+ // If this ISEQ has previously escaped EP, give up the optimization.
+ _ if iseq_escapes_ep(self.iseq) => true,
+ _ => false,
+ }
+ }
+
// Get the index of the next instruction
fn next_insn_idx(&self) -> u16 {
self.insn_idx + insn_len(self.get_opcode()) as u16
@@ -229,6 +250,33 @@ impl JITState {
}
}
+ pub fn assume_expected_cfunc(
+ &mut self,
+ asm: &mut Assembler,
+ ocb: &mut OutlinedCb,
+ class: VALUE,
+ method: ID,
+ cfunc: *mut c_void,
+ ) -> bool {
+ let cme = unsafe { rb_callable_method_entry(class, method) };
+
+ if cme.is_null() {
+ return false;
+ }
+
+ let def_type = unsafe { get_cme_def_type(cme) };
+ if def_type != VM_METHOD_TYPE_CFUNC {
+ return false;
+ }
+ if unsafe { get_mct_func(get_cme_def_body_cfunc(cme)) } != cfunc {
+ return false;
+ }
+
+ self.assume_method_lookup_stable(asm, ocb, cme);
+
+ true
+ }
+
pub fn assume_method_lookup_stable(&mut self, asm: &mut Assembler, ocb: &mut OutlinedCb, cme: CmePtr) -> Option<()> {
jit_ensure_block_entry_exit(self, asm, ocb)?;
self.method_lookup_assumptions.push(cme);
@@ -250,6 +298,19 @@ impl JITState {
true
}
+ /// Assume that base pointer is equal to environment pointer in the current ISEQ.
+ /// Return true if it's safe to assume so.
+ fn assume_no_ep_escape(&mut self, asm: &mut Assembler, ocb: &mut OutlinedCb) -> bool {
+ if jit_ensure_block_entry_exit(self, asm, ocb).is_none() {
+ return false; // out of space, give up
+ }
+ if self.escapes_ep() {
+ return false; // EP has been escaped in this ISEQ. disable the optimization to avoid an invalidation loop.
+ }
+ self.no_ep_escape = true;
+ true
+ }
+
fn get_cfp(&self) -> *mut rb_control_frame_struct {
unsafe { get_ec_cfp(self.ec) }
}
@@ -533,14 +594,36 @@ fn verify_ctx(jit: &JITState, ctx: &Context) {
unsafe { CStr::from_ptr(rb_obj_info(val)).to_str().unwrap() }
}
+ // Some types such as CString only assert the class field of the object
+ // when there has never been a singleton class created for objects of that class.
+ // Once there is a singleton class created they become their weaker
+ // `T*` variant, and we more objects should pass the verification.
+ fn relax_type_with_singleton_class_assumption(ty: Type) -> Type {
+ if let Type::CString | Type::CArray | Type::CHash = ty {
+ if has_singleton_class_of(ty.known_class().unwrap()) {
+ match ty {
+ Type::CString => return Type::TString,
+ Type::CArray => return Type::TArray,
+ Type::CHash => return Type::THash,
+ _ => (),
+ }
+ }
+ }
+
+ ty
+ }
+
// Only able to check types when at current insn
assert!(jit.at_current_insn());
let self_val = jit.peek_at_self();
let self_val_type = Type::from(self_val);
+ let learned_self_type = ctx.get_opnd_type(SelfOpnd);
+ let learned_self_type = relax_type_with_singleton_class_assumption(learned_self_type);
+
// Verify self operand type
- if self_val_type.diff(ctx.get_opnd_type(SelfOpnd)) == TypeDiff::Incompatible {
+ if self_val_type.diff(learned_self_type) == TypeDiff::Incompatible {
panic!(
"verify_ctx: ctx self type ({:?}) incompatible with actual value of self {}",
ctx.get_opnd_type(SelfOpnd),
@@ -553,6 +636,7 @@ fn verify_ctx(jit: &JITState, ctx: &Context) {
for i in 0..top_idx {
let learned_mapping = ctx.get_opnd_mapping(StackOpnd(i));
let learned_type = ctx.get_opnd_type(StackOpnd(i));
+ let learned_type = relax_type_with_singleton_class_assumption(learned_type);
let stack_val = jit.peek_at_stack(ctx, i as isize);
let val_type = Type::from(stack_val);
@@ -598,6 +682,7 @@ fn verify_ctx(jit: &JITState, ctx: &Context) {
let top_idx: usize = cmp::min(local_table_size as usize, MAX_TEMP_TYPES);
for i in 0..top_idx {
let learned_type = ctx.get_local_type(i);
+ let learned_type = relax_type_with_singleton_class_assumption(learned_type);
let local_val = jit.peek_at_local(i as i32);
let local_type = Type::from(local_val);
@@ -1384,7 +1469,7 @@ fn gen_putobject(
Some(KeepCompiling)
}
-/// Combine `putobject` and and `opt_ltlt` together if profitable, for example when
+/// Combine `putobject` and `opt_ltlt` together if profitable, for example when
/// left shifting an integer by a constant amount.
fn fuse_putobject_opt_ltlt(
jit: &mut JITState,
@@ -2203,16 +2288,22 @@ fn gen_get_lep(jit: &JITState, asm: &mut Assembler) -> Opnd {
fn gen_getlocal_generic(
jit: &mut JITState,
asm: &mut Assembler,
+ ocb: &mut OutlinedCb,
ep_offset: u32,
level: u32,
) -> Option<CodegenStatus> {
- // Load environment pointer EP (level 0) from CFP
- let ep_opnd = gen_get_ep(asm, level);
+ let local_opnd = if level == 0 && jit.assume_no_ep_escape(asm, ocb) {
+ // Load the local using SP register
+ asm.ctx.ep_opnd(-(ep_offset as i32))
+ } else {
+ // Load environment pointer EP (level 0) from CFP
+ let ep_opnd = gen_get_ep(asm, level);
- // Load the local from the block
- // val = *(vm_get_ep(GET_EP(), level) - idx);
- let offs = -(SIZEOF_VALUE_I32 * ep_offset as i32);
- let local_opnd = Opnd::mem(64, ep_opnd, offs);
+ // Load the local from the block
+ // val = *(vm_get_ep(GET_EP(), level) - idx);
+ let offs = -(SIZEOF_VALUE_I32 * ep_offset as i32);
+ Opnd::mem(64, ep_opnd, offs)
+ };
// Write the local at SP
let stack_top = if level == 0 {
@@ -2230,29 +2321,29 @@ fn gen_getlocal_generic(
fn gen_getlocal(
jit: &mut JITState,
asm: &mut Assembler,
- _ocb: &mut OutlinedCb,
+ ocb: &mut OutlinedCb,
) -> Option<CodegenStatus> {
let idx = jit.get_arg(0).as_u32();
let level = jit.get_arg(1).as_u32();
- gen_getlocal_generic(jit, asm, idx, level)
+ gen_getlocal_generic(jit, asm, ocb, idx, level)
}
fn gen_getlocal_wc0(
jit: &mut JITState,
asm: &mut Assembler,
- _ocb: &mut OutlinedCb,
+ ocb: &mut OutlinedCb,
) -> Option<CodegenStatus> {
let idx = jit.get_arg(0).as_u32();
- gen_getlocal_generic(jit, asm, idx, 0)
+ gen_getlocal_generic(jit, asm, ocb, idx, 0)
}
fn gen_getlocal_wc1(
jit: &mut JITState,
asm: &mut Assembler,
- _ocb: &mut OutlinedCb,
+ ocb: &mut OutlinedCb,
) -> Option<CodegenStatus> {
let idx = jit.get_arg(0).as_u32();
- gen_getlocal_generic(jit, asm, idx, 1)
+ gen_getlocal_generic(jit, asm, ocb, idx, 1)
}
fn gen_setlocal_generic(
@@ -2264,11 +2355,11 @@ fn gen_setlocal_generic(
) -> Option<CodegenStatus> {
let value_type = asm.ctx.get_opnd_type(StackOpnd(0));
- // Load environment pointer EP at level
- let ep_opnd = gen_get_ep(asm, level);
-
// Fallback because of write barrier
if asm.ctx.get_chain_depth() > 0 {
+ // Load environment pointer EP at level
+ let ep_opnd = gen_get_ep(asm, level);
+
// This function should not yield to the GC.
// void rb_vm_env_write(const VALUE *ep, int index, VALUE v)
let index = -(ep_offset as i64);
@@ -2286,16 +2377,27 @@ fn gen_setlocal_generic(
return Some(KeepCompiling);
}
- // Write barriers may be required when VM_ENV_FLAG_WB_REQUIRED is set, however write barriers
- // only affect heap objects being written. If we know an immediate value is being written we
- // can skip this check.
- if !value_type.is_imm() {
- // flags & VM_ENV_FLAG_WB_REQUIRED
+ let (flags_opnd, local_opnd) = if level == 0 && jit.assume_no_ep_escape(asm, ocb) {
+ // Load flags and the local using SP register
+ let local_opnd = asm.ctx.ep_opnd(-(ep_offset as i32));
+ let flags_opnd = asm.ctx.ep_opnd(VM_ENV_DATA_INDEX_FLAGS as i32);
+ (flags_opnd, local_opnd)
+ } else {
+ // Load flags and the local for the level
+ let ep_opnd = gen_get_ep(asm, level);
let flags_opnd = Opnd::mem(
64,
ep_opnd,
SIZEOF_VALUE_I32 * VM_ENV_DATA_INDEX_FLAGS as i32,
);
+ (flags_opnd, Opnd::mem(64, ep_opnd, -SIZEOF_VALUE_I32 * ep_offset as i32))
+ };
+
+ // Write barriers may be required when VM_ENV_FLAG_WB_REQUIRED is set, however write barriers
+ // only affect heap objects being written. If we know an immediate value is being written we
+ // can skip this check.
+ if !value_type.is_imm() {
+ // flags & VM_ENV_FLAG_WB_REQUIRED
asm.test(flags_opnd, VM_ENV_FLAG_WB_REQUIRED.into());
// if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0
@@ -2319,8 +2421,7 @@ fn gen_setlocal_generic(
let stack_top = asm.stack_pop(1);
// Write the value at the environment pointer
- let offs = -(SIZEOF_VALUE_I32 * ep_offset as i32);
- asm.mov(Opnd::mem(64, ep_opnd, offs), stack_top);
+ asm.mov(local_opnd, stack_top);
Some(KeepCompiling)
}
@@ -5879,8 +5980,10 @@ fn jit_rb_ary_push(
) -> bool {
asm_comment!(asm, "Array#<<");
- // rb_ary_push allocates memory for buffer extension
- jit_prepare_call_with_gc(jit, asm);
+ // rb_ary_push allocates memory for buffer extension and can raise FrozenError
+ // Not using a lazy frame here since the interpreter also has a truncated
+ // stack trace from opt_ltlt.
+ jit_prepare_non_leaf_call(jit, asm);
let item_opnd = asm.stack_opnd(0);
let ary_opnd = asm.stack_opnd(1);
@@ -6058,6 +6161,64 @@ fn gen_block_given(
asm.mov(out_opnd, block_given);
}
+// Codegen for rb_class_superclass()
+fn jit_rb_class_superclass(
+ jit: &mut JITState,
+ asm: &mut Assembler,
+ _ocb: &mut OutlinedCb,
+ _ci: *const rb_callinfo,
+ cme: *const rb_callable_method_entry_t,
+ _block: Option<crate::codegen::BlockHandler>,
+ _argc: i32,
+ _known_recv_class: Option<VALUE>,
+) -> bool {
+ extern "C" {
+ fn rb_class_superclass(klass: VALUE) -> VALUE;
+ }
+
+ if !jit_prepare_lazy_frame_call(jit, asm, cme, StackOpnd(0)) {
+ return false;
+ }
+
+ asm_comment!(asm, "Class#superclass");
+ let recv_opnd = asm.stack_opnd(0);
+ let ret = asm.ccall(rb_class_superclass as *const u8, vec![recv_opnd]);
+
+ asm.stack_pop(1);
+ let ret_opnd = asm.stack_push(Type::Unknown);
+ asm.mov(ret_opnd, ret);
+
+ true
+}
+
+fn jit_rb_case_equal(
+ jit: &mut JITState,
+ asm: &mut Assembler,
+ ocb: &mut OutlinedCb,
+ _ci: *const rb_callinfo,
+ _cme: *const rb_callable_method_entry_t,
+ _block: Option<BlockHandler>,
+ _argc: i32,
+ known_recv_class: Option<VALUE>,
+) -> bool {
+ if !jit.assume_expected_cfunc( asm, ocb, known_recv_class.unwrap(), ID!(eq), rb_obj_equal as _) {
+ return false;
+ }
+
+ asm_comment!(asm, "case_equal: {}#===", get_class_name(known_recv_class));
+
+ // Compare the arguments
+ let arg1 = asm.stack_pop(1);
+ let arg0 = asm.stack_pop(1);
+ asm.cmp(arg0, arg1);
+ let ret_opnd = asm.csel_e(Qtrue.into(), Qfalse.into());
+
+ let stack_ret = asm.stack_push(Type::UnknownImm);
+ asm.mov(stack_ret, ret_opnd);
+
+ true
+}
+
fn jit_thread_s_current(
_jit: &mut JITState,
asm: &mut Assembler,
@@ -8148,6 +8309,13 @@ fn gen_struct_aref(
}
}
+ if c_method_tracing_currently_enabled(jit) {
+ // Struct accesses need fire c_call and c_return events, which we can't support
+ // See :attr-tracing:
+ gen_counter_incr(asm, Counter::send_cfunc_tracing);
+ return None;
+ }
+
// This is a .send call and we need to adjust the stack
if flags & VM_CALL_OPT_SEND != 0 {
handle_opt_send_shift_stack(asm, argc);
@@ -8192,6 +8360,13 @@ fn gen_struct_aset(
return None;
}
+ if c_method_tracing_currently_enabled(jit) {
+ // Struct accesses need fire c_call and c_return events, which we can't support
+ // See :attr-tracing:
+ gen_counter_incr(asm, Counter::send_cfunc_tracing);
+ return None;
+ }
+
// This is a .send call and we need to adjust the stack
if flags & VM_CALL_OPT_SEND != 0 {
handle_opt_send_shift_stack(asm, argc);
@@ -8458,10 +8633,8 @@ fn gen_send_general(
// Handling the C method tracing events for attr_accessor
// methods is easier than regular C methods as we know the
// "method" we are calling into never enables those tracing
- // events. Once global invalidation runs, the code for the
- // attr_accessor is invalidated and we exit at the closest
- // instruction boundary which is always outside of the body of
- // the attr_accessor code.
+ // events. We are never inside the code that needs to be
+ // invalidated when invalidation happens.
gen_counter_incr(asm, Counter::send_cfunc_tracing);
return None;
}
@@ -8721,11 +8894,16 @@ fn gen_send_general(
}
}
+/// Get class name from a class pointer.
+fn get_class_name(class: Option<VALUE>) -> String {
+ class.and_then(|class| unsafe {
+ cstr_to_rust_string(rb_class2name(class))
+ }).unwrap_or_else(|| "Unknown".to_string())
+}
+
/// Assemble "{class_name}#{method_name}" from a class pointer and a method ID
fn get_method_name(class: Option<VALUE>, mid: u64) -> String {
- let class_name = class.and_then(|class| unsafe {
- cstr_to_rust_string(rb_class2name(class))
- }).unwrap_or_else(|| "Unknown".to_string());
+ let class_name = get_class_name(class);
let method_name = if mid != 0 {
unsafe { cstr_to_rust_string(rb_id2name(mid)) }
} else {
@@ -10060,6 +10238,10 @@ pub fn yjit_reg_method_codegen_fns() {
yjit_reg_method(rb_cString, "<<", jit_rb_str_concat);
yjit_reg_method(rb_cString, "+@", jit_rb_str_uplus);
+ yjit_reg_method(rb_cNilClass, "===", jit_rb_case_equal);
+ yjit_reg_method(rb_cTrueClass, "===", jit_rb_case_equal);
+ yjit_reg_method(rb_cFalseClass, "===", jit_rb_case_equal);
+
yjit_reg_method(rb_cArray, "empty?", jit_rb_ary_empty_p);
yjit_reg_method(rb_cArray, "length", jit_rb_ary_length);
yjit_reg_method(rb_cArray, "size", jit_rb_ary_length);
@@ -10070,6 +10252,8 @@ pub fn yjit_reg_method_codegen_fns() {
yjit_reg_method(rb_mKernel, "respond_to?", jit_obj_respond_to);
yjit_reg_method(rb_mKernel, "block_given?", jit_rb_f_block_given_p);
+ yjit_reg_method(rb_cClass, "superclass", jit_rb_class_superclass);
+
yjit_reg_method(rb_singleton_class(rb_cThread), "current", jit_thread_s_current);
}
}
diff --git a/yjit/src/core.rs b/yjit/src/core.rs
index fb7d52cc5d..cd6e649aa0 100644
--- a/yjit/src/core.rs
+++ b/yjit/src/core.rs
@@ -53,11 +53,11 @@ pub enum Type {
ImmSymbol,
TString, // An object with the T_STRING flag set, possibly an rb_cString
- CString, // An un-subclassed string of type rb_cString (can have instance vars in some cases)
+ CString, // An object that at one point had its class field equal rb_cString (creating a singleton class changes it)
TArray, // An object with the T_ARRAY flag set, possibly an rb_cArray
- CArray, // An un-subclassed array of type rb_cArray (can have instance vars in some cases)
+ CArray, // An object that at one point had its class field equal rb_cArray (creating a singleton class changes it)
THash, // An object with the T_HASH flag set, possibly an rb_cHash
- CHash, // An un-subclassed hash of type rb_cHash (can have instance vars in some cases)
+ CHash, // An object that at one point had its class field equal rb_cHash (creating a singleton class changes it)
BlockParamProxy, // A special sentinel value indicating the block parameter should be read from
// the current surrounding cfp
@@ -1138,8 +1138,12 @@ pub fn for_each_off_stack_iseq_payload<F: FnMut(&mut IseqPayload)>(mut callback:
/// Free the per-iseq payload
#[no_mangle]
-pub extern "C" fn rb_yjit_iseq_free(payload: *mut c_void) {
+pub extern "C" fn rb_yjit_iseq_free(iseq: IseqPtr) {
+ // Free invariants for the ISEQ
+ iseq_free_invariants(iseq);
+
let payload = {
+ let payload = unsafe { rb_iseq_get_yjit_payload(iseq) };
if payload.is_null() {
// Nothing to free.
return;
@@ -1266,7 +1270,8 @@ pub extern "C" fn rb_yjit_iseq_mark(payload: *mut c_void) {
/// GC callback for updating GC objects in the per-iseq payload.
/// This is a mirror of [rb_yjit_iseq_mark].
#[no_mangle]
-pub extern "C" fn rb_yjit_iseq_update_references(payload: *mut c_void) {
+pub extern "C" fn rb_yjit_iseq_update_references(iseq: IseqPtr) {
+ let payload = unsafe { rb_iseq_get_yjit_payload(iseq) };
let payload = if payload.is_null() {
// Nothing to update.
return;
@@ -1657,6 +1662,9 @@ impl JITState {
for klass in self.no_singleton_class_assumptions {
track_no_singleton_class_assumption(blockref, klass);
}
+ if self.no_ep_escape {
+ track_no_ep_escape_assumption(blockref, self.iseq);
+ }
blockref
}
@@ -1798,6 +1806,13 @@ impl Context {
return Opnd::mem(64, SP, offset);
}
+ /// Get an operand for the adjusted environment pointer address using SP register.
+ /// This is valid only when a Binding object hasn't been created for the frame.
+ pub fn ep_opnd(&self, offset: i32) -> Opnd {
+ let ep_offset = self.get_stack_size() as i32 + 1;
+ self.sp_opnd(-ep_offset + offset)
+ }
+
/// Stop using a register for a given stack temp.
/// This allows us to reuse the register for a value that we know is dead
/// and will no longer be used (e.g. popped stack temp).
@@ -2643,6 +2658,12 @@ fn regenerate_branch(cb: &mut CodeBlock, branch: &Branch) {
branch.get_target_address(1).map(|addr| Target::CodePtr(addr)),
);
+ // If the entire block is the branch and the block could be invalidated,
+ // we need to pad to ensure there is room for invalidation patching.
+ if branch.start_addr == block.start_addr && branch_terminates_block && block.entry_exit.is_some() {
+ asm.pad_inval_patch();
+ }
+
// Rewrite the branch
let old_write_pos = cb.get_write_pos();
let old_dropped_bytes = cb.has_dropped_bytes();
@@ -3124,6 +3145,12 @@ pub fn defer_compilation(
// Likely a stub due to the increased chain depth
let target0_address = branch.set_target(0, blockid, &next_ctx, ocb);
+ // Pad the block if it has the potential to be invalidated. This must be
+ // done before gen_fn() in case the jump is overwritten by a fallthrough.
+ if jit.block_entry_exit.is_some() {
+ asm.pad_inval_patch();
+ }
+
// Call the branch generation function
asm_comment!(asm, "defer_compilation");
asm.mark_branch_start(&branch);
@@ -3307,9 +3334,10 @@ pub fn invalidate_block_version(blockref: &BlockRef) {
assert!(
cb.get_write_ptr() <= block_end,
- "invalidation wrote past end of block (code_size: {:?}, new_size: {})",
+ "invalidation wrote past end of block (code_size: {:?}, new_size: {}, start_addr: {:?})",
block.code_size(),
cb.get_write_ptr().as_offset() - block_start.as_offset(),
+ block.start_addr.raw_ptr(cb),
);
cb.set_write_ptr(cur_pos);
cb.set_dropped_bytes(cur_dropped_bytes);
diff --git a/yjit/src/cruby.rs b/yjit/src/cruby.rs
index 9547e3fa2c..68c0304b06 100644
--- a/yjit/src/cruby.rs
+++ b/yjit/src/cruby.rs
@@ -83,7 +83,7 @@
#![allow(non_upper_case_globals)]
use std::convert::From;
-use std::ffi::CString;
+use std::ffi::{CString, CStr};
use std::os::raw::{c_char, c_int, c_uint};
use std::panic::{catch_unwind, UnwindSafe};
@@ -170,6 +170,7 @@ pub use rb_iseq_encoded_size as get_iseq_encoded_size;
pub use rb_get_iseq_body_local_iseq as get_iseq_body_local_iseq;
pub use rb_get_iseq_body_iseq_encoded as get_iseq_body_iseq_encoded;
pub use rb_get_iseq_body_stack_max as get_iseq_body_stack_max;
+pub use rb_get_iseq_body_type as get_iseq_body_type;
pub use rb_get_iseq_flags_has_lead as get_iseq_flags_has_lead;
pub use rb_get_iseq_flags_has_opt as get_iseq_flags_has_opt;
pub use rb_get_iseq_flags_has_kw as get_iseq_flags_has_kw;
@@ -207,8 +208,6 @@ pub use rb_RCLASS_ORIGIN as RCLASS_ORIGIN;
/// Helper so we can get a Rust string for insn_name()
pub fn insn_name(opcode: usize) -> String {
- use std::ffi::CStr;
-
unsafe {
// Look up Ruby's NULL-terminated insn name string
let op_name = raw_insn_name(VALUE(opcode));
@@ -607,7 +606,6 @@ pub fn rust_str_to_sym(str: &str) -> VALUE {
pub fn cstr_to_rust_string(c_char_ptr: *const c_char) -> Option<String> {
assert!(c_char_ptr != std::ptr::null());
- use std::ffi::CStr;
let c_str: &CStr = unsafe { CStr::from_ptr(c_char_ptr) };
match c_str.to_str() {
@@ -619,17 +617,20 @@ pub fn cstr_to_rust_string(c_char_ptr: *const c_char) -> Option<String> {
/// A location in Rust code for integrating with debugging facilities defined in C.
/// Use the [src_loc!] macro to crate an instance.
pub struct SourceLocation {
- pub file: CString,
+ pub file: &'static CStr,
pub line: c_int,
}
/// Make a [SourceLocation] at the current spot.
macro_rules! src_loc {
() => {
- // NOTE(alan): `CString::new` allocates so we might want to limit this to debug builds.
- $crate::cruby::SourceLocation {
- file: std::ffi::CString::new(file!()).unwrap(), // ASCII source file paths
- line: line!().try_into().unwrap(), // not that many lines
+ {
+ // Nul-terminated string with static lifetime, make a CStr out of it safely.
+ let file: &'static str = concat!(file!(), '\0');
+ $crate::cruby::SourceLocation {
+ file: unsafe { std::ffi::CStr::from_ptr(file.as_ptr().cast()) },
+ line: line!().try_into().unwrap(),
+ }
}
};
}
@@ -667,17 +668,16 @@ where
Err(_) => {
// Theoretically we can recover from some of these panics,
// but it's too late if the unwind reaches here.
- use std::{process, str};
let _ = catch_unwind(|| {
// IO functions can panic too.
eprintln!(
"YJIT panicked while holding VM lock acquired at {}:{}. Aborting...",
- str::from_utf8(loc.file.as_bytes()).unwrap_or("<not utf8>"),
+ loc.file.to_string_lossy(),
line,
);
});
- process::abort();
+ std::process::abort();
}
};
@@ -804,6 +804,7 @@ pub(crate) mod ids {
name: hash content: b"hash"
name: respond_to_missing content: b"respond_to_missing?"
name: to_ary content: b"to_ary"
+ name: eq content: b"=="
}
}
diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs
index 359227d60d..a03c2d0f00 100644
--- a/yjit/src/cruby_bindings.inc.rs
+++ b/yjit/src/cruby_bindings.inc.rs
@@ -478,6 +478,16 @@ pub struct iseq_inline_iv_cache_entry {
pub struct iseq_inline_cvar_cache_entry {
pub entry: *mut rb_cvar_class_tbl_entry,
}
+pub const ISEQ_TYPE_TOP: rb_iseq_type = 0;
+pub const ISEQ_TYPE_METHOD: rb_iseq_type = 1;
+pub const ISEQ_TYPE_BLOCK: rb_iseq_type = 2;
+pub const ISEQ_TYPE_CLASS: rb_iseq_type = 3;
+pub const ISEQ_TYPE_RESCUE: rb_iseq_type = 4;
+pub const ISEQ_TYPE_ENSURE: rb_iseq_type = 5;
+pub const ISEQ_TYPE_EVAL: rb_iseq_type = 6;
+pub const ISEQ_TYPE_MAIN: rb_iseq_type = 7;
+pub const ISEQ_TYPE_PLAIN: rb_iseq_type = 8;
+pub type rb_iseq_type = u32;
pub const BUILTIN_ATTR_LEAF: rb_builtin_attr = 1;
pub const BUILTIN_ATTR_SINGLE_NOARG_LEAF: rb_builtin_attr = 2;
pub const BUILTIN_ATTR_INLINE_BLOCK: rb_builtin_attr = 4;
@@ -962,6 +972,7 @@ extern "C" {
pub static mut rb_mKernel: VALUE;
pub static mut rb_cBasicObject: VALUE;
pub static mut rb_cArray: VALUE;
+ pub static mut rb_cClass: VALUE;
pub static mut rb_cFalseClass: VALUE;
pub static mut rb_cFloat: VALUE;
pub static mut rb_cHash: VALUE;
@@ -1013,6 +1024,7 @@ extern "C" {
pub fn rb_attr_get(obj: VALUE, name: ID) -> VALUE;
pub fn rb_obj_info_dump(obj: VALUE);
pub fn rb_class_allocate_instance(klass: VALUE) -> VALUE;
+ pub fn rb_obj_equal(obj1: VALUE, obj2: VALUE) -> VALUE;
pub fn rb_reg_new_ary(ary: VALUE, options: ::std::os::raw::c_int) -> VALUE;
pub fn rb_ary_tmp_new_from_values(
arg1: VALUE,
@@ -1153,6 +1165,7 @@ extern "C" {
pub fn rb_get_iseq_body_local_table_size(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
pub fn rb_get_iseq_body_iseq_encoded(iseq: *const rb_iseq_t) -> *mut VALUE;
pub fn rb_get_iseq_body_stack_max(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
+ pub fn rb_get_iseq_body_type(iseq: *const rb_iseq_t) -> rb_iseq_type;
pub fn rb_get_iseq_flags_has_lead(iseq: *const rb_iseq_t) -> bool;
pub fn rb_get_iseq_flags_has_opt(iseq: *const rb_iseq_t) -> bool;
pub fn rb_get_iseq_flags_has_kw(iseq: *const rb_iseq_t) -> bool;
diff --git a/yjit/src/invariants.rs b/yjit/src/invariants.rs
index e460293440..6639fd677b 100644
--- a/yjit/src/invariants.rs
+++ b/yjit/src/invariants.rs
@@ -59,6 +59,11 @@ pub struct Invariants {
/// there has been a singleton class for the class after boot, so you cannot
/// assume no singleton class going forward.
no_singleton_classes: HashMap<VALUE, HashSet<BlockRef>>,
+
+ /// A map from an ISEQ to a set of blocks that assume base pointer is equal
+ /// to environment pointer. When the set is empty, it means that EP has been
+ /// escaped in the ISEQ.
+ no_ep_escape_iseqs: HashMap<IseqPtr, HashSet<BlockRef>>,
}
/// Private singleton instance of the invariants global struct.
@@ -76,6 +81,7 @@ impl Invariants {
constant_state_blocks: HashMap::new(),
block_constant_states: HashMap::new(),
no_singleton_classes: HashMap::new(),
+ no_ep_escape_iseqs: HashMap::new(),
});
}
}
@@ -154,6 +160,31 @@ pub fn has_singleton_class_of(klass: VALUE) -> bool {
.map_or(false, |blocks| blocks.is_empty())
}
+/// Track that a block will assume that base pointer is equal to environment pointer.
+pub fn track_no_ep_escape_assumption(uninit_block: BlockRef, iseq: IseqPtr) {
+ Invariants::get_instance()
+ .no_ep_escape_iseqs
+ .entry(iseq)
+ .or_default()
+ .insert(uninit_block);
+}
+
+/// Returns true if a given ISEQ has previously escaped an environment.
+pub fn iseq_escapes_ep(iseq: IseqPtr) -> bool {
+ Invariants::get_instance()
+ .no_ep_escape_iseqs
+ .get(&iseq)
+ .map_or(false, |blocks| blocks.is_empty())
+}
+
+/// Forget an ISEQ remembered in invariants
+pub fn iseq_free_invariants(iseq: IseqPtr) {
+ if unsafe { INVARIANTS.is_none() } {
+ return;
+ }
+ Invariants::get_instance().no_ep_escape_iseqs.remove(&iseq);
+}
+
// Checks rb_method_basic_definition_p and registers the current block for invalidation if method
// lookup changes.
// A "basic method" is one defined during VM boot, so we can use this to check assumptions based on
@@ -317,7 +348,7 @@ pub extern "C" fn rb_yjit_constant_state_changed(id: ID) {
/// Callback for marking GC objects inside [Invariants].
/// See `struct yjijt_root_struct` in C.
#[no_mangle]
-pub extern "C" fn rb_yjit_root_mark() {
+pub extern "C" fn rb_yjit_root_mark(_: *mut c_void) {
// Call rb_gc_mark on exit location's raw_samples to
// wrap frames in a GC allocated object. This needs to be called
// at the same time as root mark.
@@ -345,6 +376,23 @@ pub extern "C" fn rb_yjit_root_mark() {
}
}
+#[no_mangle]
+pub extern "C" fn rb_yjit_root_update_references(_: *mut c_void) {
+ if unsafe { INVARIANTS.is_none() } {
+ return;
+ }
+ let no_ep_escape_iseqs = &mut Invariants::get_instance().no_ep_escape_iseqs;
+
+ // Make a copy of the table with updated ISEQ keys
+ let mut updated_copy = HashMap::with_capacity(no_ep_escape_iseqs.len());
+ for (iseq, blocks) in mem::take(no_ep_escape_iseqs) {
+ let new_iseq = unsafe { rb_gc_location(iseq.into()) }.as_iseq();
+ updated_copy.insert(new_iseq, blocks);
+ }
+
+ *no_ep_escape_iseqs = updated_copy;
+}
+
/// Remove all invariant assumptions made by the block by removing the block as
/// as a key in all of the relevant tables.
/// For safety, the block has to be initialized and the vm lock must be held.
@@ -420,6 +468,10 @@ pub fn block_assumptions_free(blockref: BlockRef) {
for (_, blocks) in invariants.no_singleton_classes.iter_mut() {
blocks.remove(&blockref);
}
+ // Remove tracking for blocks assuming EP doesn't escape
+ for (_, blocks) in invariants.no_ep_escape_iseqs.iter_mut() {
+ blocks.remove(&blockref);
+ }
}
/// Callback from the opt_setinlinecache instruction in the interpreter.
@@ -497,22 +549,53 @@ pub extern "C" fn rb_yjit_invalidate_no_singleton_class(klass: VALUE) {
// We apply this optimization only to Array, Hash, and String for now.
if unsafe { [rb_cArray, rb_cHash, rb_cString].contains(&klass) } {
- let no_singleton_classes = &mut Invariants::get_instance().no_singleton_classes;
- match no_singleton_classes.get_mut(&klass) {
+ with_vm_lock(src_loc!(), || {
+ let no_singleton_classes = &mut Invariants::get_instance().no_singleton_classes;
+ match no_singleton_classes.get_mut(&klass) {
+ Some(blocks) => {
+ // Invalidate existing blocks and let has_singleton_class_of()
+ // return true when they are compiled again
+ for block in mem::take(blocks) {
+ invalidate_block_version(&block);
+ incr_counter!(invalidate_no_singleton_class);
+ }
+ }
+ None => {
+ // Let has_singleton_class_of() return true for this class
+ no_singleton_classes.insert(klass, HashSet::new());
+ }
+ }
+ });
+ }
+}
+
+/// Invalidate blocks for a given ISEQ that assumes environment pointer is
+/// equal to base pointer.
+#[no_mangle]
+pub extern "C" fn rb_yjit_invalidate_ep_is_bp(iseq: IseqPtr) {
+ // Skip tracking EP escapes on boot. We don't need to invalidate anything during boot.
+ if unsafe { INVARIANTS.is_none() } {
+ return;
+ }
+
+ with_vm_lock(src_loc!(), || {
+ // If an EP escape for this ISEQ is detected for the first time, invalidate all blocks
+ // associated to the ISEQ.
+ let no_ep_escape_iseqs = &mut Invariants::get_instance().no_ep_escape_iseqs;
+ match no_ep_escape_iseqs.get_mut(&iseq) {
Some(blocks) => {
- // Invalidate existing blocks and let has_singleton_class_of()
- // return true when they are compiled again
+ // Invalidate existing blocks and make jit.ep_is_bp() return false
for block in mem::take(blocks) {
invalidate_block_version(&block);
- incr_counter!(invalidate_no_singleton_class);
+ incr_counter!(invalidate_ep_escape);
}
}
None => {
- // Let has_singleton_class_of() return true for this class
- no_singleton_classes.insert(klass, HashSet::new());
+ // Let jit.ep_is_bp() return false for this ISEQ
+ no_ep_escape_iseqs.insert(iseq, HashSet::new());
}
}
- }
+ });
}
// Invalidate all generated code and patch C method return code to contain
diff --git a/yjit/src/stats.rs b/yjit/src/stats.rs
index 0a63fab8b0..6ffe28f12a 100644
--- a/yjit/src/stats.rs
+++ b/yjit/src/stats.rs
@@ -268,7 +268,7 @@ macro_rules! make_counters {
/// The list of counters that are available without --yjit-stats.
/// They are incremented only by `incr_counter!` and don't use `gen_counter_incr`.
-pub const DEFAULT_COUNTERS: [Counter; 16] = [
+pub const DEFAULT_COUNTERS: [Counter; 17] = [
Counter::code_gc_count,
Counter::compiled_iseq_entry,
Counter::cold_iseq_entry,
@@ -286,6 +286,7 @@ pub const DEFAULT_COUNTERS: [Counter; 16] = [
Counter::invalidate_constant_state_bump,
Counter::invalidate_constant_ic_fill,
Counter::invalidate_no_singleton_class,
+ Counter::invalidate_ep_escape,
];
/// Macro to increase a counter by name and count
@@ -568,6 +569,7 @@ make_counters! {
invalidate_constant_state_bump,
invalidate_constant_ic_fill,
invalidate_no_singleton_class,
+ invalidate_ep_escape,
// Currently, it's out of the ordinary (might be impossible) for YJIT to leave gaps in
// executable memory, so this should be 0.