diff --git a/.github/actions/setup/directories/action.yml b/.github/actions/setup/directories/action.yml index 83492b38622ac0..63abd4ae58b8bd 100644 --- a/.github/actions/setup/directories/action.yml +++ b/.github/actions/setup/directories/action.yml @@ -93,7 +93,7 @@ runs: path: ${{ inputs.srcdir }} fetch-depth: ${{ inputs.fetch-depth }} - - uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ${{ inputs.srcdir }}/.downloaded-cache key: downloaded-cache @@ -164,7 +164,7 @@ runs: echo final='rmdir ${{ inputs.builddir }}' >> $GITHUB_OUTPUT - name: clean - uses: gacts/run-and-post-run@674528335da98a7afc80915ff2b4b860a0b3553a # v1.4.0 + uses: gacts/run-and-post-run@7aec950f3b114c4fcf6012070c3709ecff0eb6f8 # v1.4.0 with: working-directory: post: | diff --git a/.github/workflows/annocheck.yml b/.github/workflows/annocheck.yml index 94ebe6cb12136e..175b31a2bb2923 100644 --- a/.github/workflows/annocheck.yml +++ b/.github/workflows/annocheck.yml @@ -74,7 +74,7 @@ jobs: builddir: build makeup: true - - uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0 + - uses: ruby/setup-ruby@5f19ec79cedfadb78ab837f95b87734d0003c899 # v1.173.0 with: ruby-version: '3.0' bundler: none diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml index 6f51aa5eab0671..36962338f9114a 100644 --- a/.github/workflows/baseruby.yml +++ b/.github/workflows/baseruby.yml @@ -51,7 +51,7 @@ jobs: - ruby-3.3 steps: - - uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0 + - uses: ruby/setup-ruby@5f19ec79cedfadb78ab837f95b87734d0003c899 # v1.173.0 with: ruby-version: ${{ matrix.ruby }} bundler: none diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml index c150948e8c3c0d..153d456e89db35 100644 --- a/.github/workflows/check_dependencies.yml +++ b/.github/workflows/check_dependencies.yml @@ -55,7 +55,7 @@ jobs: - uses: ./.github/actions/setup/directories - - uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0 + - uses: ruby/setup-ruby@5f19ec79cedfadb78ab837f95b87734d0003c899 # v1.173.0 with: ruby-version: '3.0' bundler: none diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 3e7ca81ddc748a..430a2c950d21b6 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -59,7 +59,7 @@ jobs: os: ubuntu-latest # ruby analysis used large memory. We need to use a larger runner. - language: ruby - os: ${{ github.repository == 'ruby/ruby' && 'macos-arm-oss' || 'macos-14' }} + os: ${{ github.repository == 'ruby/ruby' && 'macos-arm-oss' || 'ubuntu-latest' }} steps: - name: Checkout repository @@ -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@05963f47d870e2cb19a537396c1f668a348c7d8f # v3.24.8 + uses: github/codeql-action/init@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@05963f47d870e2cb19a537396c1f668a348c7d8f # v3.24.8 + uses: github/codeql-action/autobuild@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@05963f47d870e2cb19a537396c1f668a348c7d8f # v3.24.8 + uses: github/codeql-action/analyze@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9 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@05963f47d870e2cb19a537396c1f668a348c7d8f # v3.24.8 + uses: github/codeql-action/upload-sarif@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9 with: sarif_file: sarif-results/${{ matrix.language }}.sarif continue-on-error: true diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml index 12fda6f5a24687..9a7855b78475b5 100644 --- a/.github/workflows/compilers.yml +++ b/.github/workflows/compilers.yml @@ -265,7 +265,7 @@ jobs: if: ${{ (matrix.entry.static-exts || '') != '' }} - name: Clean up ext/Setup - uses: gacts/run-and-post-run@674528335da98a7afc80915ff2b4b860a0b3553a # v1.4.0 + uses: gacts/run-and-post-run@7aec950f3b114c4fcf6012070c3709ecff0eb6f8 # v1.4.0 with: shell: bash working-directory: build diff --git a/.github/workflows/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml index 5858507ae73763..ca9e63f1ec8749 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@c9c4182bf1b97f5224aee3906fd373f6b61b4526 # v1.6.0 + uses: dependabot/fetch-metadata@0fb21704c18a42ce5aa8d720ea4b912f5e6babef # v2.0.0 id: metadata - name: Wait for status checks diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 48e20181503be8..c5d88e30d70a6c 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -24,26 +24,22 @@ jobs: make: strategy: matrix: - test_task: ['check'] - test_opts: [''] - os: - - macos-12 - - macos-13 - - ${{ github.repository == 'ruby/ruby' && 'macos-arm-oss' || 'macos-14' }} include: + - test_task: check - test_task: test-all test_opts: --repeat-count=2 - os: ${{ github.repository == 'ruby/ruby' && 'macos-arm-oss' || 'macos-14' }} - test_task: test-bundler-parallel - os: ${{ github.repository == 'ruby/ruby' && 'macos-arm-oss' || 'macos-14' }} - test_task: test-bundled-gems - os: ${{ github.repository == 'ruby/ruby' && 'macos-arm-oss' || 'macos-14' }} + - test_task: check + os: macos-12 + - test_task: check + os: macos-13 fail-fast: false env: GITPULLOPTIONS: --no-tags origin ${{ github.ref }} - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.os || (github.repository == 'ruby/ruby' && 'macos-arm-oss' || 'macos-14')}} if: >- ${{!(false diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml index 893d11945443cd..7b9db05f116832 100644 --- a/.github/workflows/mingw.yml +++ b/.github/workflows/mingw.yml @@ -66,7 +66,7 @@ jobs: steps: - name: Set up Ruby & MSYS2 - uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0 + uses: ruby/setup-ruby@5f19ec79cedfadb78ab837f95b87734d0003c899 # v1.173.0 with: ruby-version: ${{ matrix.baseruby }} diff --git a/.github/workflows/prism.yml b/.github/workflows/prism.yml index 48a88f23fdc003..49058c232f616a 100644 --- a/.github/workflows/prism.yml +++ b/.github/workflows/prism.yml @@ -95,13 +95,13 @@ jobs: RUBY_TESTOPTS: '-q --tty=no --excludes-dir="../src/test/.excludes-prism" --exclude="test_ast.rb" --exclude="test_regexp.rb" --exclude="error_highlight/test_error_highlight.rb" --exclude="prism/encoding_test.rb"' RUN_OPTS: ${{ matrix.run_opts }} - # - name: make test-spec - # run: | - # $SETARCH make -s test-spec RUN_OPTS="$RUN_OPTS" - # timeout-minutes: 10 - # env: - # GNUMAKEFLAGS: '' - # RUN_OPTS: ${{ matrix.run_opts }} + - name: make test-prism-spec + run: | + $SETARCH make -s test-prism-spec SPECOPTS="$SPECOPTS" + timeout-minutes: 10 + env: + GNUMAKEFLAGS: '' + SPECOPTS: "-T -W:no-experimental -T --parser=prism" - uses: ./.github/actions/slack with: diff --git a/.github/workflows/rjit-bindgen.yml b/.github/workflows/rjit-bindgen.yml index 1196b6bf929ffb..eea5a0c0151dd7 100644 --- a/.github/workflows/rjit-bindgen.yml +++ b/.github/workflows/rjit-bindgen.yml @@ -47,7 +47,7 @@ jobs: steps: - name: Set up Ruby - uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0 + uses: ruby/setup-ruby@5f19ec79cedfadb78ab837f95b87734d0003c899 # v1.173.0 with: ruby-version: '3.1' diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 51bce58de44e81..2889d4d47c4747 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -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@05963f47d870e2cb19a537396c1f668a348c7d8f # v2.1.27 + uses: github/codeql-action/upload-sarif@1b1aada464948af03b950897e5eb522f92603cc2 # v2.1.27 with: sarif_file: results.sarif diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml index b4ff6055f50939..c14b4ee03845fd 100644 --- a/.github/workflows/spec_guards.yml +++ b/.github/workflows/spec_guards.yml @@ -47,7 +47,7 @@ jobs: steps: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0 + - uses: ruby/setup-ruby@5f19ec79cedfadb78ab837f95b87734d0003c899 # v1.173.0 with: ruby-version: ${{ matrix.ruby }} bundler: none diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 853f4e4ab76724..62b55845b9e8d8 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -24,32 +24,26 @@ jobs: make: strategy: matrix: - os: [ubuntu-22.04, ubuntu-20.04] - test_task: [check] - arch: [''] - configure: ['cppflags=-DVM_CHECK_MODE'] - # specifying other jobs with `include` to avoid redundant tests include: + - test_task: check + configure: 'cppflags=-DVM_CHECK_MODE' - test_task: check arch: i686 - os: ubuntu-22.04 - test_task: check configure: '--disable-yjit' - os: ubuntu-22.04 - test_task: check configure: '--enable-shared --enable-load-relative' - os: ubuntu-22.04 - test_task: test-bundler-parallel - os: ubuntu-22.04 - test_task: test-bundled-gems - os: ubuntu-22.04 + - test_task: check + os: ubuntu-20.04 fail-fast: false env: GITPULLOPTIONS: --no-tags origin ${{ github.ref }} RUBY_DEBUG: ci - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.os || 'ubuntu-22.04' }} if: >- ${{!(false @@ -71,7 +65,7 @@ jobs: with: arch: ${{ matrix.arch }} - - uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0 + - uses: ruby/setup-ruby@5f19ec79cedfadb78ab837f95b87734d0003c899 # v1.173.0 with: ruby-version: '3.0' bundler: none diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 3c0b9de411c937..ad7ea13cbf3e45 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -100,7 +100,7 @@ jobs: run: | echo "WASI_SDK_PATH=/opt/wasi-sdk" >> $GITHUB_ENV - - uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0 + - uses: ruby/setup-ruby@5f19ec79cedfadb78ab837f95b87734d0003c899 # v1.173.0 with: ruby-version: '3.0' bundler: none @@ -120,7 +120,7 @@ jobs: --host wasm32-unknown-wasi \ --with-baseruby=$PWD/../baseruby/install/bin/ruby \ --with-static-linked-ext \ - --with-ext=bigdecimal,cgi/escape,continuation,coverage,date,dbm,digest/bubblebabble,digest,digest/md5,digest/rmd160,digest/sha1,digest/sha2,etc,fcntl,fiber,gdbm,json,json/generator,json/parser,nkf,objspace,pathname,racc/cparse,rbconfig/sizeof,ripper,stringio,strscan,monitor \ + --with-ext=cgi/escape,continuation,coverage,date,digest/bubblebabble,digest,digest/md5,digest/rmd160,digest/sha1,digest/sha2,etc,fcntl,json,json/generator,json/parser,objspace,pathname,rbconfig/sizeof,ripper,stringio,strscan,monitor \ LDFLAGS=" \ -Xlinker --stack-first \ -Xlinker -z -Xlinker stack-size=16777216 \ diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 13b91f9656e06e..db2235eb6c972a 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -91,13 +91,13 @@ jobs: ${{ steps.find-tools.outputs.needs }} if: ${{ steps.find-tools.outputs.needs != '' }} - - uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0 + - uses: ruby/setup-ruby@5f19ec79cedfadb78ab837f95b87734d0003c899 # v1.173.0 with: ruby-version: '3.0' bundler: none windows-toolchain: none - - uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: C:\vcpkg\downloads key: ${{ runner.os }}-vcpkg-download-${{ env.OS_VER }}-${{ github.sha }} @@ -105,7 +105,7 @@ jobs: ${{ runner.os }}-vcpkg-download-${{ env.OS_VER }}- ${{ runner.os }}-vcpkg-download- - - uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: C:\vcpkg\installed key: ${{ runner.os }}-vcpkg-installed-${{ env.OS_VER }}-${{ github.sha }} diff --git a/.github/workflows/yjit-ubuntu.yml b/.github/workflows/yjit-ubuntu.yml index 439daf793819d1..d93fb24e419bac 100644 --- a/.github/workflows/yjit-ubuntu.yml +++ b/.github/workflows/yjit-ubuntu.yml @@ -145,7 +145,7 @@ jobs: if: ${{ matrix.rust_version }} run: rustup install ${{ matrix.rust_version }} --profile minimal - - uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0 + - uses: ruby/setup-ruby@5f19ec79cedfadb78ab837f95b87734d0003c899 # v1.173.0 with: ruby-version: '3.0' bundler: none diff --git a/.travis.yml b/.travis.yml index 5298885697eb05..06de3dd493263f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -121,6 +121,7 @@ matrix: fast_finish: true before_script: + - lscpu - ./autogen.sh - mkdir build - cd build diff --git a/NEWS.md b/NEWS.md index feda4c1e792bac..adc0ac5daaa0ef 100644 --- a/NEWS.md +++ b/NEWS.md @@ -11,7 +11,7 @@ Note that each entry is kept to a minimum, see links for details. as if they were frozen. If they are mutated a deprecation warning is emited. These warnings can be enabled with `-W:deprecated` or by setting `Warning[:deprecated] = true`. To disable this change you can run Ruby with the `--disable-frozen-string-literal` command line - argument. [Feature #20205] + argument. [[Feature #20205]] * `it` is added to reference a block parameter. [[Feature #18980]] @@ -31,7 +31,7 @@ Note: We're only listing outstanding class updates. * Exception * Exception#set_backtrace now accepts arrays of `Thread::Backtrace::Location`. - `Kernel#raise`, `Thread#raise` and `Fiber#raise` also accept this new format. [Feature #13557] + `Kernel#raise`, `Thread#raise` and `Fiber#raise` also accept this new format. [[Feature #13557]] ## Stdlib updates @@ -45,7 +45,8 @@ The following default gems are updated. * irb 1.12.0 * net-http 0.4.1 * prism 0.24.0 -* reline 0.5.0.pre.1 +* rdoc 6.6.3.1 +* reline 0.5.0 * resolv 0.4.0 * stringio 3.1.1 * strscan 3.1.1 @@ -74,7 +75,7 @@ The following bundled gems are promoted from default gems. * drb 2.2.1 * nkf 0.2.0 * syslog 0.1.2 -* csv 3.2.8 +* csv 3.3.0 See GitHub releases like [GitHub Releases of Logger](https://github.com/ruby/logger/releases) or changelog for details of the default gems or bundled gems. @@ -108,11 +109,13 @@ See GitHub releases like [GitHub Releases of Logger](https://github.com/ruby/log ## JIT +[Feature #13557]: https://bugs.ruby-lang.org/issues/13557 [Feature #16495]: https://bugs.ruby-lang.org/issues/16495 [Feature #18980]: https://bugs.ruby-lang.org/issues/18980 [Feature #19117]: https://bugs.ruby-lang.org/issues/19117 [Bug #19918]: https://bugs.ruby-lang.org/issues/19918 [Bug #20064]: https://bugs.ruby-lang.org/issues/20064 [Feature #20182]: https://bugs.ruby-lang.org/issues/20182 +[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 diff --git a/common.mk b/common.mk index d668fa8424343a..21ceaa3f01279b 100644 --- a/common.mk +++ b/common.mk @@ -471,8 +471,6 @@ ruby.imp: $(COMMONOBJS) $(Q){ \ $(NM) -Pgp $(COMMONOBJS) | \ awk 'BEGIN{print "#!"}; $$2~/^[A-TV-Z]$$/&&$$1!~/^$(SYMBOL_PREFIX)(Init_|InitVM_|ruby_static_id_|.*_threadptr_|rb_ec_)|^\./{print $$1}'; \ - ($(CHDIR) $(srcdir) && \ - exec sed -n '/^RJIT_FUNC_EXPORTED/!d;N;s/.*\n\(rb_[a-zA-Z_0-9]*\).*/$(SYMBOL_PREFIX)\1/p' cont.c gc.c thread*c vm*.c) \ } | \ sort -u -o $@ @@ -1007,6 +1005,15 @@ yes-test-spec: yes-test-spec-precheck $(ACTIONS_ENDGROUP) no-test-spec: +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 \ + $(srcdir)/spec/mspec/bin/mspec run -B $(srcdir)/spec/default.mspec -B $(srcdir)/spec/prism.mspec $(MSPECOPT) $(SPECOPTS) + $(ACTIONS_ENDGROUP) +no-test-prism-spec: + check: $(DOT_WAIT) test-spec RUNNABLE = $(LIBRUBY_RELATIVE:no=un)-runnable diff --git a/cont.c b/cont.c index b07b5e380f4b0a..c6a94e0709f369 100644 --- a/cont.c +++ b/cont.c @@ -796,6 +796,9 @@ static inline void ec_switch(rb_thread_t *th, rb_fiber_t *fiber) { rb_execution_context_t *ec = &fiber->cont.saved_ec; +#ifdef RUBY_ASAN_ENABLED + ec->machine.asan_fake_stack_handle = asan_get_thread_fake_stack_handle(); +#endif rb_ractor_set_current_ec(th->ractor, th->ec = ec); // ruby_current_execution_context_ptr = th->ec = ec; @@ -1023,13 +1026,8 @@ cont_mark(void *ptr) cont->machine.stack + cont->machine.stack_size); } else { - /* fiber */ - const rb_fiber_t *fiber = (rb_fiber_t*)cont; - - if (!FIBER_TERMINATED_P(fiber)) { - rb_gc_mark_locations(cont->machine.stack, - cont->machine.stack + cont->machine.stack_size); - } + /* fiber machine context is marked as part of rb_execution_context_mark, no need to + * do anything here. */ } } @@ -1568,11 +1566,10 @@ fiber_setcontext(rb_fiber_t *new_fiber, rb_fiber_t *old_fiber) } } - /* exchange machine_stack_start between old_fiber and new_fiber */ + /* these values are used in rb_gc_mark_machine_context to mark the fiber's stack. */ old_fiber->cont.saved_ec.machine.stack_start = th->ec->machine.stack_start; + old_fiber->cont.saved_ec.machine.stack_end = FIBER_TERMINATED_P(old_fiber) ? NULL : th->ec->machine.stack_end; - /* old_fiber->machine.stack_end should be NULL */ - old_fiber->cont.saved_ec.machine.stack_end = NULL; // if (DEBUG) fprintf(stderr, "fiber_setcontext: %p[%p] -> %p[%p]\n", (void*)old_fiber, old_fiber->stack.base, (void*)new_fiber, new_fiber->stack.base); diff --git a/ext/-test-/fatal/depend b/ext/-test-/fatal/depend index 730a72e52a4180..45a8c659c4780d 100644 --- a/ext/-test-/fatal/depend +++ b/ext/-test-/fatal/depend @@ -1,4 +1,322 @@ # AUTOGENERATED DEPENDENCIES START +init.o: $(RUBY_EXTCONF_H) +init.o: $(arch_hdrdir)/ruby/config.h +init.o: $(hdrdir)/ruby.h +init.o: $(hdrdir)/ruby/assert.h +init.o: $(hdrdir)/ruby/backward.h +init.o: $(hdrdir)/ruby/backward/2/assume.h +init.o: $(hdrdir)/ruby/backward/2/attributes.h +init.o: $(hdrdir)/ruby/backward/2/bool.h +init.o: $(hdrdir)/ruby/backward/2/inttypes.h +init.o: $(hdrdir)/ruby/backward/2/limits.h +init.o: $(hdrdir)/ruby/backward/2/long_long.h +init.o: $(hdrdir)/ruby/backward/2/stdalign.h +init.o: $(hdrdir)/ruby/backward/2/stdarg.h +init.o: $(hdrdir)/ruby/defines.h +init.o: $(hdrdir)/ruby/intern.h +init.o: $(hdrdir)/ruby/internal/abi.h +init.o: $(hdrdir)/ruby/internal/anyargs.h +init.o: $(hdrdir)/ruby/internal/arithmetic.h +init.o: $(hdrdir)/ruby/internal/arithmetic/char.h +init.o: $(hdrdir)/ruby/internal/arithmetic/double.h +init.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +init.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +init.o: $(hdrdir)/ruby/internal/arithmetic/int.h +init.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +init.o: $(hdrdir)/ruby/internal/arithmetic/long.h +init.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +init.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +init.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +init.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +init.o: $(hdrdir)/ruby/internal/arithmetic/short.h +init.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +init.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +init.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +init.o: $(hdrdir)/ruby/internal/assume.h +init.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +init.o: $(hdrdir)/ruby/internal/attr/artificial.h +init.o: $(hdrdir)/ruby/internal/attr/cold.h +init.o: $(hdrdir)/ruby/internal/attr/const.h +init.o: $(hdrdir)/ruby/internal/attr/constexpr.h +init.o: $(hdrdir)/ruby/internal/attr/deprecated.h +init.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +init.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +init.o: $(hdrdir)/ruby/internal/attr/error.h +init.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +init.o: $(hdrdir)/ruby/internal/attr/forceinline.h +init.o: $(hdrdir)/ruby/internal/attr/format.h +init.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +init.o: $(hdrdir)/ruby/internal/attr/noalias.h +init.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +init.o: $(hdrdir)/ruby/internal/attr/noexcept.h +init.o: $(hdrdir)/ruby/internal/attr/noinline.h +init.o: $(hdrdir)/ruby/internal/attr/nonnull.h +init.o: $(hdrdir)/ruby/internal/attr/noreturn.h +init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +init.o: $(hdrdir)/ruby/internal/attr/pure.h +init.o: $(hdrdir)/ruby/internal/attr/restrict.h +init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +init.o: $(hdrdir)/ruby/internal/attr/warning.h +init.o: $(hdrdir)/ruby/internal/attr/weakref.h +init.o: $(hdrdir)/ruby/internal/cast.h +init.o: $(hdrdir)/ruby/internal/compiler_is.h +init.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +init.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +init.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +init.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +init.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +init.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +init.o: $(hdrdir)/ruby/internal/compiler_since.h +init.o: $(hdrdir)/ruby/internal/config.h +init.o: $(hdrdir)/ruby/internal/constant_p.h +init.o: $(hdrdir)/ruby/internal/core.h +init.o: $(hdrdir)/ruby/internal/core/rarray.h +init.o: $(hdrdir)/ruby/internal/core/rbasic.h +init.o: $(hdrdir)/ruby/internal/core/rbignum.h +init.o: $(hdrdir)/ruby/internal/core/rclass.h +init.o: $(hdrdir)/ruby/internal/core/rdata.h +init.o: $(hdrdir)/ruby/internal/core/rfile.h +init.o: $(hdrdir)/ruby/internal/core/rhash.h +init.o: $(hdrdir)/ruby/internal/core/robject.h +init.o: $(hdrdir)/ruby/internal/core/rregexp.h +init.o: $(hdrdir)/ruby/internal/core/rstring.h +init.o: $(hdrdir)/ruby/internal/core/rstruct.h +init.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +init.o: $(hdrdir)/ruby/internal/ctype.h +init.o: $(hdrdir)/ruby/internal/dllexport.h +init.o: $(hdrdir)/ruby/internal/dosish.h +init.o: $(hdrdir)/ruby/internal/error.h +init.o: $(hdrdir)/ruby/internal/eval.h +init.o: $(hdrdir)/ruby/internal/event.h +init.o: $(hdrdir)/ruby/internal/fl_type.h +init.o: $(hdrdir)/ruby/internal/gc.h +init.o: $(hdrdir)/ruby/internal/glob.h +init.o: $(hdrdir)/ruby/internal/globals.h +init.o: $(hdrdir)/ruby/internal/has/attribute.h +init.o: $(hdrdir)/ruby/internal/has/builtin.h +init.o: $(hdrdir)/ruby/internal/has/c_attribute.h +init.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +init.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +init.o: $(hdrdir)/ruby/internal/has/extension.h +init.o: $(hdrdir)/ruby/internal/has/feature.h +init.o: $(hdrdir)/ruby/internal/has/warning.h +init.o: $(hdrdir)/ruby/internal/intern/array.h +init.o: $(hdrdir)/ruby/internal/intern/bignum.h +init.o: $(hdrdir)/ruby/internal/intern/class.h +init.o: $(hdrdir)/ruby/internal/intern/compar.h +init.o: $(hdrdir)/ruby/internal/intern/complex.h +init.o: $(hdrdir)/ruby/internal/intern/cont.h +init.o: $(hdrdir)/ruby/internal/intern/dir.h +init.o: $(hdrdir)/ruby/internal/intern/enum.h +init.o: $(hdrdir)/ruby/internal/intern/enumerator.h +init.o: $(hdrdir)/ruby/internal/intern/error.h +init.o: $(hdrdir)/ruby/internal/intern/eval.h +init.o: $(hdrdir)/ruby/internal/intern/file.h +init.o: $(hdrdir)/ruby/internal/intern/hash.h +init.o: $(hdrdir)/ruby/internal/intern/io.h +init.o: $(hdrdir)/ruby/internal/intern/load.h +init.o: $(hdrdir)/ruby/internal/intern/marshal.h +init.o: $(hdrdir)/ruby/internal/intern/numeric.h +init.o: $(hdrdir)/ruby/internal/intern/object.h +init.o: $(hdrdir)/ruby/internal/intern/parse.h +init.o: $(hdrdir)/ruby/internal/intern/proc.h +init.o: $(hdrdir)/ruby/internal/intern/process.h +init.o: $(hdrdir)/ruby/internal/intern/random.h +init.o: $(hdrdir)/ruby/internal/intern/range.h +init.o: $(hdrdir)/ruby/internal/intern/rational.h +init.o: $(hdrdir)/ruby/internal/intern/re.h +init.o: $(hdrdir)/ruby/internal/intern/ruby.h +init.o: $(hdrdir)/ruby/internal/intern/select.h +init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +init.o: $(hdrdir)/ruby/internal/intern/signal.h +init.o: $(hdrdir)/ruby/internal/intern/sprintf.h +init.o: $(hdrdir)/ruby/internal/intern/string.h +init.o: $(hdrdir)/ruby/internal/intern/struct.h +init.o: $(hdrdir)/ruby/internal/intern/thread.h +init.o: $(hdrdir)/ruby/internal/intern/time.h +init.o: $(hdrdir)/ruby/internal/intern/variable.h +init.o: $(hdrdir)/ruby/internal/intern/vm.h +init.o: $(hdrdir)/ruby/internal/interpreter.h +init.o: $(hdrdir)/ruby/internal/iterator.h +init.o: $(hdrdir)/ruby/internal/memory.h +init.o: $(hdrdir)/ruby/internal/method.h +init.o: $(hdrdir)/ruby/internal/module.h +init.o: $(hdrdir)/ruby/internal/newobj.h +init.o: $(hdrdir)/ruby/internal/scan_args.h +init.o: $(hdrdir)/ruby/internal/special_consts.h +init.o: $(hdrdir)/ruby/internal/static_assert.h +init.o: $(hdrdir)/ruby/internal/stdalign.h +init.o: $(hdrdir)/ruby/internal/stdbool.h +init.o: $(hdrdir)/ruby/internal/symbol.h +init.o: $(hdrdir)/ruby/internal/value.h +init.o: $(hdrdir)/ruby/internal/value_type.h +init.o: $(hdrdir)/ruby/internal/variable.h +init.o: $(hdrdir)/ruby/internal/warning_push.h +init.o: $(hdrdir)/ruby/internal/xmalloc.h +init.o: $(hdrdir)/ruby/missing.h +init.o: $(hdrdir)/ruby/ruby.h +init.o: $(hdrdir)/ruby/st.h +init.o: $(hdrdir)/ruby/subst.h +init.o: init.c +invalid.o: $(RUBY_EXTCONF_H) +invalid.o: $(arch_hdrdir)/ruby/config.h +invalid.o: $(hdrdir)/ruby.h +invalid.o: $(hdrdir)/ruby/assert.h +invalid.o: $(hdrdir)/ruby/backward.h +invalid.o: $(hdrdir)/ruby/backward/2/assume.h +invalid.o: $(hdrdir)/ruby/backward/2/attributes.h +invalid.o: $(hdrdir)/ruby/backward/2/bool.h +invalid.o: $(hdrdir)/ruby/backward/2/inttypes.h +invalid.o: $(hdrdir)/ruby/backward/2/limits.h +invalid.o: $(hdrdir)/ruby/backward/2/long_long.h +invalid.o: $(hdrdir)/ruby/backward/2/stdalign.h +invalid.o: $(hdrdir)/ruby/backward/2/stdarg.h +invalid.o: $(hdrdir)/ruby/defines.h +invalid.o: $(hdrdir)/ruby/intern.h +invalid.o: $(hdrdir)/ruby/internal/abi.h +invalid.o: $(hdrdir)/ruby/internal/anyargs.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/char.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/double.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/int.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/long.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/short.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +invalid.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +invalid.o: $(hdrdir)/ruby/internal/assume.h +invalid.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +invalid.o: $(hdrdir)/ruby/internal/attr/artificial.h +invalid.o: $(hdrdir)/ruby/internal/attr/cold.h +invalid.o: $(hdrdir)/ruby/internal/attr/const.h +invalid.o: $(hdrdir)/ruby/internal/attr/constexpr.h +invalid.o: $(hdrdir)/ruby/internal/attr/deprecated.h +invalid.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +invalid.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +invalid.o: $(hdrdir)/ruby/internal/attr/error.h +invalid.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +invalid.o: $(hdrdir)/ruby/internal/attr/forceinline.h +invalid.o: $(hdrdir)/ruby/internal/attr/format.h +invalid.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +invalid.o: $(hdrdir)/ruby/internal/attr/noalias.h +invalid.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +invalid.o: $(hdrdir)/ruby/internal/attr/noexcept.h +invalid.o: $(hdrdir)/ruby/internal/attr/noinline.h +invalid.o: $(hdrdir)/ruby/internal/attr/nonnull.h +invalid.o: $(hdrdir)/ruby/internal/attr/noreturn.h +invalid.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +invalid.o: $(hdrdir)/ruby/internal/attr/pure.h +invalid.o: $(hdrdir)/ruby/internal/attr/restrict.h +invalid.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +invalid.o: $(hdrdir)/ruby/internal/attr/warning.h +invalid.o: $(hdrdir)/ruby/internal/attr/weakref.h +invalid.o: $(hdrdir)/ruby/internal/cast.h +invalid.o: $(hdrdir)/ruby/internal/compiler_is.h +invalid.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +invalid.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +invalid.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +invalid.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +invalid.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +invalid.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +invalid.o: $(hdrdir)/ruby/internal/compiler_since.h +invalid.o: $(hdrdir)/ruby/internal/config.h +invalid.o: $(hdrdir)/ruby/internal/constant_p.h +invalid.o: $(hdrdir)/ruby/internal/core.h +invalid.o: $(hdrdir)/ruby/internal/core/rarray.h +invalid.o: $(hdrdir)/ruby/internal/core/rbasic.h +invalid.o: $(hdrdir)/ruby/internal/core/rbignum.h +invalid.o: $(hdrdir)/ruby/internal/core/rclass.h +invalid.o: $(hdrdir)/ruby/internal/core/rdata.h +invalid.o: $(hdrdir)/ruby/internal/core/rfile.h +invalid.o: $(hdrdir)/ruby/internal/core/rhash.h +invalid.o: $(hdrdir)/ruby/internal/core/robject.h +invalid.o: $(hdrdir)/ruby/internal/core/rregexp.h +invalid.o: $(hdrdir)/ruby/internal/core/rstring.h +invalid.o: $(hdrdir)/ruby/internal/core/rstruct.h +invalid.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +invalid.o: $(hdrdir)/ruby/internal/ctype.h +invalid.o: $(hdrdir)/ruby/internal/dllexport.h +invalid.o: $(hdrdir)/ruby/internal/dosish.h +invalid.o: $(hdrdir)/ruby/internal/error.h +invalid.o: $(hdrdir)/ruby/internal/eval.h +invalid.o: $(hdrdir)/ruby/internal/event.h +invalid.o: $(hdrdir)/ruby/internal/fl_type.h +invalid.o: $(hdrdir)/ruby/internal/gc.h +invalid.o: $(hdrdir)/ruby/internal/glob.h +invalid.o: $(hdrdir)/ruby/internal/globals.h +invalid.o: $(hdrdir)/ruby/internal/has/attribute.h +invalid.o: $(hdrdir)/ruby/internal/has/builtin.h +invalid.o: $(hdrdir)/ruby/internal/has/c_attribute.h +invalid.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +invalid.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +invalid.o: $(hdrdir)/ruby/internal/has/extension.h +invalid.o: $(hdrdir)/ruby/internal/has/feature.h +invalid.o: $(hdrdir)/ruby/internal/has/warning.h +invalid.o: $(hdrdir)/ruby/internal/intern/array.h +invalid.o: $(hdrdir)/ruby/internal/intern/bignum.h +invalid.o: $(hdrdir)/ruby/internal/intern/class.h +invalid.o: $(hdrdir)/ruby/internal/intern/compar.h +invalid.o: $(hdrdir)/ruby/internal/intern/complex.h +invalid.o: $(hdrdir)/ruby/internal/intern/cont.h +invalid.o: $(hdrdir)/ruby/internal/intern/dir.h +invalid.o: $(hdrdir)/ruby/internal/intern/enum.h +invalid.o: $(hdrdir)/ruby/internal/intern/enumerator.h +invalid.o: $(hdrdir)/ruby/internal/intern/error.h +invalid.o: $(hdrdir)/ruby/internal/intern/eval.h +invalid.o: $(hdrdir)/ruby/internal/intern/file.h +invalid.o: $(hdrdir)/ruby/internal/intern/hash.h +invalid.o: $(hdrdir)/ruby/internal/intern/io.h +invalid.o: $(hdrdir)/ruby/internal/intern/load.h +invalid.o: $(hdrdir)/ruby/internal/intern/marshal.h +invalid.o: $(hdrdir)/ruby/internal/intern/numeric.h +invalid.o: $(hdrdir)/ruby/internal/intern/object.h +invalid.o: $(hdrdir)/ruby/internal/intern/parse.h +invalid.o: $(hdrdir)/ruby/internal/intern/proc.h +invalid.o: $(hdrdir)/ruby/internal/intern/process.h +invalid.o: $(hdrdir)/ruby/internal/intern/random.h +invalid.o: $(hdrdir)/ruby/internal/intern/range.h +invalid.o: $(hdrdir)/ruby/internal/intern/rational.h +invalid.o: $(hdrdir)/ruby/internal/intern/re.h +invalid.o: $(hdrdir)/ruby/internal/intern/ruby.h +invalid.o: $(hdrdir)/ruby/internal/intern/select.h +invalid.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +invalid.o: $(hdrdir)/ruby/internal/intern/signal.h +invalid.o: $(hdrdir)/ruby/internal/intern/sprintf.h +invalid.o: $(hdrdir)/ruby/internal/intern/string.h +invalid.o: $(hdrdir)/ruby/internal/intern/struct.h +invalid.o: $(hdrdir)/ruby/internal/intern/thread.h +invalid.o: $(hdrdir)/ruby/internal/intern/time.h +invalid.o: $(hdrdir)/ruby/internal/intern/variable.h +invalid.o: $(hdrdir)/ruby/internal/intern/vm.h +invalid.o: $(hdrdir)/ruby/internal/interpreter.h +invalid.o: $(hdrdir)/ruby/internal/iterator.h +invalid.o: $(hdrdir)/ruby/internal/memory.h +invalid.o: $(hdrdir)/ruby/internal/method.h +invalid.o: $(hdrdir)/ruby/internal/module.h +invalid.o: $(hdrdir)/ruby/internal/newobj.h +invalid.o: $(hdrdir)/ruby/internal/scan_args.h +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/symbol.h +invalid.o: $(hdrdir)/ruby/internal/value.h +invalid.o: $(hdrdir)/ruby/internal/value_type.h +invalid.o: $(hdrdir)/ruby/internal/variable.h +invalid.o: $(hdrdir)/ruby/internal/warning_push.h +invalid.o: $(hdrdir)/ruby/internal/xmalloc.h +invalid.o: $(hdrdir)/ruby/missing.h +invalid.o: $(hdrdir)/ruby/ruby.h +invalid.o: $(hdrdir)/ruby/st.h +invalid.o: $(hdrdir)/ruby/subst.h +invalid.o: invalid.c rb_fatal.o: $(RUBY_EXTCONF_H) rb_fatal.o: $(arch_hdrdir)/ruby/config.h rb_fatal.o: $(hdrdir)/ruby.h @@ -158,4 +476,5 @@ 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-/fatal/extconf.rb b/ext/-test-/fatal/extconf.rb index d5849c073328b5..ca51178a18b200 100644 --- a/ext/-test-/fatal/extconf.rb +++ b/ext/-test-/fatal/extconf.rb @@ -1,2 +1,3 @@ # frozen_string_literal: false -create_makefile("-test-/fatal/rb_fatal") +require_relative "../auto_ext.rb" +auto_ext diff --git a/ext/-test-/fatal/init.c b/ext/-test-/fatal/init.c new file mode 100644 index 00000000000000..3b71708789502c --- /dev/null +++ b/ext/-test-/fatal/init.c @@ -0,0 +1,10 @@ +#include "ruby.h" + +#define init(n) {void Init_##n(VALUE klass); Init_##n(klass);} + +void +Init_fatal(void) +{ + VALUE klass = rb_define_module("Bug"); + TEST_INIT_FUNCS(init); +} diff --git a/ext/-test-/fatal/invalid.c b/ext/-test-/fatal/invalid.c new file mode 100644 index 00000000000000..f0726edb521152 --- /dev/null +++ b/ext/-test-/fatal/invalid.c @@ -0,0 +1,28 @@ +#include + +#if SIZEOF_LONG == SIZEOF_VOIDP +# define NUM2PTR(x) (void *)NUM2ULONG(x) +#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP +# define NUM2PTR(x) (void *)NUM2ULL(x) +#endif + +static VALUE +invalid_call(VALUE obj, VALUE address) +{ + typedef VALUE (*func_type)(VALUE); + + return (*(func_type)NUM2PTR(address))(obj); +} + +static VALUE +invalid_access(VALUE obj, VALUE address) +{ + return *(VALUE *)NUM2PTR(address) == obj ? Qtrue : Qfalse; +} + +void +Init_invalid(VALUE mBug) +{ + rb_define_singleton_method(mBug, "invalid_call", invalid_call, 1); + rb_define_singleton_method(mBug, "invalid_access", invalid_access, 1); +} diff --git a/ext/-test-/fatal/rb_fatal.c b/ext/-test-/fatal/rb_fatal.c index eedbc51f8b83d6..6c7bb89628fdd4 100644 --- a/ext/-test-/fatal/rb_fatal.c +++ b/ext/-test-/fatal/rb_fatal.c @@ -13,8 +13,7 @@ ruby_fatal(VALUE obj, VALUE msg) } void -Init_rb_fatal(void) +Init_rb_fatal(VALUE mBug) { - VALUE mBug = rb_define_module("Bug"); rb_define_singleton_method(mBug, "rb_fatal", ruby_fatal, 1); } diff --git a/ext/extmk.rb b/ext/extmk.rb index e52fbb4208d85f..6c7c7aeab777e4 100755 --- a/ext/extmk.rb +++ b/ext/extmk.rb @@ -499,26 +499,30 @@ def $mflags.defined?(var) mandatory_exts = {} withes, withouts = [["--with", nil], ["--without", default_exclude_exts]].collect {|w, d| if !(w = %w[-extensions -ext].collect {|o|arg_config(w+o)}).any? - d ? proc {|c1| d.any?(&c1)} : proc {true} + d ? proc {|&c1| d.any?(&c1)} : proc {true} elsif (w = w.grep(String)).empty? proc {true} else w = w.collect {|o| o.split(/,/)}.flatten w.collect! {|o| o == '+' ? d : o}.flatten! - proc {|c1| w.any?(&c1)} + proc {|&c1| w.any?(&c1)} end } cond = proc {|ext, *| - withes.call(proc {|n| - !n or (mandatory_exts[ext] = true if File.fnmatch(n, ext)) - }) and - !withouts.call(proc {|n| File.fnmatch(n, ext)}) + withes.call {|n| !n or (mandatory_exts[ext] = true if File.fnmatch(n, ext))} and + !withouts.call {|n| File.fnmatch(n, ext)} } ($extension || %w[*]).each do |e| e = e.sub(/\A(?:\.\/)+/, '') incl, excl = Dir.glob("#{e}/**/extconf.rb", base: "#$top_srcdir/#{ext_prefix}").collect {|d| File.dirname(d) }.partition {|ext| + if @gemname + ext = ext[%r[\A[^/]+]] # extract gem name + Dir.glob("*.gemspec", base: "#$top_srcdir/#{ext_prefix}/#{ext}") do |g| + break ext = g if ext.start_with?("#{g.chomp!(".gemspec")}-") + end + end with_config(ext, &cond) } incl.sort! diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index 4119c72c48767d..dd3732d0a876fc 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -13,14 +13,7 @@ require "mkmf" -ssl_dirs = nil -if defined?(::TruffleRuby) - # Always respect the openssl prefix chosen by truffle/openssl-prefix - require 'truffle/openssl-prefix' - ssl_dirs = dir_config("openssl", ENV["OPENSSL_PREFIX"]) -else - ssl_dirs = dir_config("openssl") -end +ssl_dirs = dir_config("openssl") dir_config_given = ssl_dirs.any? _, ssl_ldir = ssl_dirs diff --git a/ext/ripper/ripper_init.c.tmpl b/ext/ripper/ripper_init.c.tmpl index 2386f54c0e6fb8..894cbc0b447b51 100644 --- a/ext/ripper/ripper_init.c.tmpl +++ b/ext/ripper/ripper_init.c.tmpl @@ -94,7 +94,8 @@ ripper_s_allocate(VALUE klass) &parser_data_type, r); #ifdef UNIVERSAL_PARSER - r->p = rb_parser_params_allocate(); + const rb_parser_config_t *config = rb_ruby_parser_config(); + r->p = rb_ripper_parser_params_allocate(config); #else r->p = rb_ruby_ripper_parser_allocate(); #endif diff --git a/ext/win32ole/win32ole.gemspec b/ext/win32ole/win32ole.gemspec index 9c137a5d700610..625916ae1765cb 100644 --- a/ext/win32ole/win32ole.gemspec +++ b/ext/win32ole/win32ole.gemspec @@ -23,9 +23,11 @@ Gem::Specification.new do |spec| spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = spec.homepage - spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do - `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } - end + pathspecs = %W[ + :(exclude,literal)#{File.basename(__FILE__)} + :^/bin/ :^/test/ :^/rakelib/ :^/.git* :^/Gemfile* :^/Rakefile* + ] + spec.files = IO.popen(%w[git ls-files -z --] + pathspecs, chdir: __dir__, err: IO::NULL, exception: false, &:read).split("\x0") spec.bindir = "exe" spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] diff --git a/gc.c b/gc.c index bdc038b1ed6a50..32502707b92b45 100644 --- a/gc.c +++ b/gc.c @@ -1025,7 +1025,7 @@ typedef struct rb_objspace { rb_postponed_job_handle_t finalize_deferred_pjob; #ifdef RUBY_ASAN_ENABLED - rb_execution_context_t *marking_machine_context_ec; + const rb_execution_context_t *marking_machine_context_ec; #endif const struct rb_callcache *global_cc_cache_table[VM_GLOBAL_CC_CACHE_TABLE_SIZE]; // vm_eval.c @@ -2700,6 +2700,40 @@ heap_page_free(rb_objspace_t *objspace, struct heap_page *page, bool global_page free(page); } +static void * +rb_aligned_malloc(size_t alignment, size_t size) +{ + /* alignment must be a power of 2 */ + GC_ASSERT(((alignment - 1) & alignment) == 0); + GC_ASSERT(alignment % sizeof(void*) == 0); + + void *res; + +#if defined __MINGW32__ + res = __mingw_aligned_malloc(size, alignment); +#elif defined _WIN32 + void *_aligned_malloc(size_t, size_t); + res = _aligned_malloc(size, alignment); +#elif defined(HAVE_POSIX_MEMALIGN) + if (posix_memalign(&res, alignment, size) != 0) { + return NULL; + } +#elif defined(HAVE_MEMALIGN) + res = memalign(alignment, size); +#else + char* aligned; + res = malloc(alignment + size + sizeof(void*)); + aligned = (char*)res + alignment + sizeof(void*); + aligned -= ((VALUE)aligned & (alignment - 1)); + ((void**)aligned)[-1] = res; + res = (void*)aligned; +#endif + + GC_ASSERT((uintptr_t)res % alignment == 0); + + return res; +} + static void set_sorted_page_list_range(struct heap_page **sorted_page_list, size_t list_allocated_pages, uintptr_t *lo, uintptr_t *hi) { @@ -8363,11 +8397,11 @@ gc_mark_machine_stack_location_maybe(rb_objspace_t *objspace, VALUE obj) gc_mark_maybe(objspace, obj); #ifdef RUBY_ASAN_ENABLED - rb_execution_context_t *ec = objspace->marking_machine_context_ec; + const rb_execution_context_t *ec = objspace->marking_machine_context_ec; void *fake_frame_start; void *fake_frame_end; bool is_fake_frame = asan_get_fake_stack_extents( - ec->thread_ptr->asan_fake_stack_handle, obj, + ec->machine.asan_fake_stack_handle, obj, ec->machine.stack_start, ec->machine.stack_end, &fake_frame_start, &fake_frame_end ); @@ -8452,13 +8486,25 @@ mark_current_machine_context(rb_objspace_t *objspace, rb_execution_context_t *ec #endif void -rb_gc_mark_machine_stack(const rb_execution_context_t *ec) +rb_gc_mark_machine_context(const rb_execution_context_t *ec) { + rb_objspace_t *objspace = &rb_objspace; +#ifdef RUBY_ASAN_ENABLED + objspace->marking_machine_context_ec = ec; +#endif + VALUE *stack_start, *stack_end; + GET_STACK_BOUNDS(stack_start, stack_end, 0); RUBY_DEBUG_LOG("ec->th:%u stack_start:%p stack_end:%p", rb_ec_thread_ptr(ec)->serial, stack_start, stack_end); - rb_gc_mark_locations(stack_start, stack_end); + each_stack_location(objspace, ec, stack_start, stack_end, gc_mark_machine_stack_location_maybe); + int num_regs = sizeof(ec->machine.regs)/(sizeof(VALUE)); + each_location(objspace, (VALUE*)&ec->machine.regs, num_regs, gc_mark_machine_stack_location_maybe); + +#ifdef RUBY_ASAN_ENABLED + objspace->marking_machine_context_ec = NULL; +#endif } static void @@ -13382,7 +13428,9 @@ gc_compact_stats(VALUE self) static void root_obj_check_moved_i(const char *category, VALUE obj, void *data) { - if (gc_object_moved_p(&rb_objspace, obj)) { + rb_objspace_t *objspace = data; + + if (gc_object_moved_p(objspace, obj)) { rb_bug("ROOT %s points to MOVED: %p -> %s", category, (void *)obj, obj_info(rb_gc_location(obj))); } } @@ -13399,9 +13447,11 @@ reachable_object_check_moved_i(VALUE ref, void *data) static int heap_check_moved_i(void *vstart, void *vend, size_t stride, void *data) { + rb_objspace_t *objspace = data; + VALUE v = (VALUE)vstart; for (; v != (VALUE)vend; v += stride) { - if (gc_object_moved_p(&rb_objspace, v)) { + if (gc_object_moved_p(objspace, v)) { /* Moved object still on the heap, something may have a reference. */ } else { @@ -13566,8 +13616,8 @@ gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE do gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qfalse, Qtrue); - objspace_reachable_objects_from_root(objspace, root_obj_check_moved_i, NULL); - objspace_each_objects(objspace, heap_check_moved_i, NULL, TRUE); + objspace_reachable_objects_from_root(objspace, root_obj_check_moved_i, objspace); + objspace_each_objects(objspace, heap_check_moved_i, objspace, TRUE); objspace->rcompactor.compare_func = NULL; return gc_compact_stats(self); @@ -14740,40 +14790,6 @@ rb_memerror(void) EC_JUMP_TAG(ec, TAG_RAISE); } -void * -rb_aligned_malloc(size_t alignment, size_t size) -{ - /* alignment must be a power of 2 */ - GC_ASSERT(((alignment - 1) & alignment) == 0); - GC_ASSERT(alignment % sizeof(void*) == 0); - - void *res; - -#if defined __MINGW32__ - res = __mingw_aligned_malloc(size, alignment); -#elif defined _WIN32 - void *_aligned_malloc(size_t, size_t); - res = _aligned_malloc(size, alignment); -#elif defined(HAVE_POSIX_MEMALIGN) - if (posix_memalign(&res, alignment, size) != 0) { - return NULL; - } -#elif defined(HAVE_MEMALIGN) - res = memalign(alignment, size); -#else - char* aligned; - res = malloc(alignment + size + sizeof(void*)); - aligned = (char*)res + alignment + sizeof(void*); - aligned -= ((VALUE)aligned & (alignment - 1)); - ((void**)aligned)[-1] = res; - res = (void*)aligned; -#endif - - GC_ASSERT((uintptr_t)res % alignment == 0); - - return res; -} - static void rb_aligned_free(void *ptr, size_t size) { diff --git a/gems/bundled_gems b/gems/bundled_gems index f64651592dd33f..00a49537de3f86 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -6,11 +6,8 @@ # - revision: revision in repository-url to test # if `revision` is not given, "v"+`version` or `version` will be used. -# Waiting for https://github.com/minitest/minitest/pull/991 -minitest 5.22.3 https://github.com/Shopify/minitest b5f5202575894796e00109a8f8a5041b778991ee - -# Waiting for https://github.com/ruby/power_assert/pull/48 -power_assert 2.0.3 https://github.com/ruby/power_assert 78dd2ab3ccd93796d83c0b35b978c39bfabb938c +minitest 5.22.3 https://github.com/minitest/minitest 287b35d60c8e19c11ba090efc6eeb225325a8520 +power_assert 2.0.3 https://github.com/ruby/power_assert 84e85124c5014a139af39161d484156cfe87a9ed rake 13.1.0 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 @@ -36,4 +33,4 @@ rinda 0.2.0 https://github.com/ruby/rinda drb 2.2.1 https://github.com/ruby/drb nkf 0.2.0 https://github.com/ruby/nkf syslog 0.1.2 https://github.com/ruby/syslog -csv 3.2.8 https://github.com/ruby/csv +csv 3.3.0 https://github.com/ruby/csv diff --git a/include/ruby/internal/core/rbasic.h b/include/ruby/internal/core/rbasic.h index 4617f743a79a20..a1477e260073b3 100644 --- a/include/ruby/internal/core/rbasic.h +++ b/include/ruby/internal/core/rbasic.h @@ -56,22 +56,20 @@ enum ruby_rvalue_flags { }; /** - * Ruby's object's, base components. Every single ruby objects have them in - * common. + * Ruby object's base components. All Ruby objects have them in common. */ struct RUBY_ALIGNAS(SIZEOF_VALUE) RBasic { /** - * Per-object flags. Each ruby objects have their own characteristics - * apart from their classes. For instance whether an object is frozen or - * not is not controlled by its class. This is where such properties are - * stored. + * Per-object flags. Each Ruby object has its own characteristics apart + * from its class. For instance, whether an object is frozen or not is not + * controlled by its class. This is where such properties are stored. * * @see enum ::ruby_fl_type * - * @note This is ::VALUE rather than an enum for alignment purpose. Back + * @note This is ::VALUE rather than an enum for alignment purposes. Back * in the 1990s there were no such thing like `_Alignas` in C. */ VALUE flags; @@ -79,10 +77,10 @@ RBasic { /** * Class of an object. Every object has its class. Also, everything is an * object in Ruby. This means classes are also objects. Classes have - * their own classes, classes of classes have their classes, too ... and - * it recursively continues forever. + * their own classes, classes of classes have their classes too, and it + * recursively continues forever. * - * Also note the `const` qualifier. In ruby an object cannot "change" its + * Also note the `const` qualifier. In Ruby, an object cannot "change" its * class. */ const VALUE klass; diff --git a/include/ruby/io.h b/include/ruby/io.h index be5681df3b7979..e9dfeda5b1214b 100644 --- a/include/ruby/io.h +++ b/include/ruby/io.h @@ -137,7 +137,124 @@ struct rb_io_encoding { VALUE ecopts; }; -struct rb_io; +#ifndef HAVE_RB_IO_T +#define HAVE_RB_IO_T 1 +/** Ruby's IO, metadata and buffers. */ +struct rb_io { + /** The IO's Ruby level counterpart. */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + VALUE self; + + /** stdio ptr for read/write, if available. */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + FILE *stdio_file; + + /** file descriptor. */ + RBIMPL_ATTR_DEPRECATED(("rb_io_descriptor")) + int fd; + + /** mode flags: FMODE_XXXs */ + RBIMPL_ATTR_DEPRECATED(("rb_io_mode")) + int mode; + + /** child's pid (for pipes) */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + rb_pid_t pid; + + /** number of lines read */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + int lineno; + + /** pathname for file */ + RBIMPL_ATTR_DEPRECATED(("rb_io_path")) + VALUE pathv; + + /** finalize proc */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + void (*finalize)(struct rb_io*,int); + + /** Write buffer. */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + rb_io_buffer_t wbuf; + + /** + * (Byte) read buffer. Note also that there is a field called + * ::rb_io_t::cbuf, which also concerns read IO. + */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + rb_io_buffer_t rbuf; + + /** + * Duplex IO object, if set. + * + * @see rb_io_set_write_io() + */ + RBIMPL_ATTR_DEPRECATED(("rb_io_get_write_io")) + VALUE tied_io_for_writing; + + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + struct rb_io_encoding encs; /**< Decomposed encoding flags. */ + + /** Encoding converter used when reading from this IO. */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + rb_econv_t *readconv; + + /** + * rb_io_ungetc() destination. This buffer is read before checking + * ::rb_io_t::rbuf + */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + rb_io_buffer_t cbuf; + + /** Encoding converter used when writing to this IO. */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + rb_econv_t *writeconv; + + /** + * This is, when set, an instance of ::rb_cString which holds the "common" + * encoding. Write conversion can convert strings twice... In case + * conversion from encoding X to encoding Y does not exist, Ruby finds an + * encoding Z that bridges the two, so that X to Z to Y conversion happens. + */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + VALUE writeconv_asciicompat; + + /** Whether ::rb_io_t::writeconv is already set up. */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + int writeconv_initialized; + + /** + * Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before + * initialising ::rb_io_t::writeconv. + */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + int writeconv_pre_ecflags; + + /** + * Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising + * ::rb_io_t::writeconv. + */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + VALUE writeconv_pre_ecopts; + + /** + * This is a Ruby level mutex. It avoids multiple threads to write to an + * IO at once; helps for instance rb_io_puts() to ensure newlines right + * next to its arguments. + * + * This of course doesn't help inter-process IO interleaves, though. + */ + RBIMPL_ATTR_DEPRECATED(("with no replacement")) + VALUE write_lock; + + /** + * The timeout associated with this IO when performing blocking operations. + */ + RBIMPL_ATTR_DEPRECATED(("rb_io_timeout/rb_io_set_timeout")) + VALUE timeout; +}; +#endif + typedef struct rb_io rb_io_t; /** @alias{rb_io_enc_t} */ diff --git a/internal/gc.h b/internal/gc.h index c506430d52399a..b1ed297ef8b7c8 100644 --- a/internal/gc.h +++ b/internal/gc.h @@ -247,10 +247,6 @@ VALUE rb_gc_deactivate(rb_vm_t *vm); struct rb_objspace *get_objspace_of_value(VALUE v); void ruby_gc_set_params(void); void rb_copy_wb_protected_attribute(VALUE dest, VALUE obj); -#if __has_attribute(alloc_align) -__attribute__((__alloc_align__(1))) -#endif -RUBY_ATTR_MALLOC void *rb_aligned_malloc(size_t, size_t) RUBY_ATTR_ALLOC_SIZE((2)); size_t rb_size_mul_or_raise(size_t, size_t, VALUE); /* used in compile.c */ size_t rb_size_mul_add_or_raise(size_t, size_t, size_t, VALUE); /* used in iseq.h */ size_t rb_malloc_grow_capa(size_t current_capacity, size_t type_size); diff --git a/internal/parse.h b/internal/parse.h index e05b2bc02f5dd4..fc78836e5c48e4 100644 --- a/internal/parse.h +++ b/internal/parse.h @@ -105,6 +105,9 @@ long rb_ruby_ripper_column(rb_parser_t *p); long rb_ruby_ripper_token_len(rb_parser_t *p); rb_parser_string_t *rb_ruby_ripper_lex_lastline(rb_parser_t *p); VALUE rb_ruby_ripper_lex_state_name(struct parser_params *p, int state); +#ifdef UNIVERSAL_PARSER +rb_parser_t *rb_ripper_parser_params_allocate(const rb_parser_config_t *config); +#endif struct parser_params *rb_ruby_ripper_parser_allocate(void); #endif diff --git a/internal/ruby_parser.h b/internal/ruby_parser.h index 7b4c71526894f5..1c59851f0d7eda 100644 --- a/internal/ruby_parser.h +++ b/internal/ruby_parser.h @@ -12,6 +12,7 @@ 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 diff --git a/iseq.c b/iseq.c index c7e0a3a1fff9c5..66c98ab1f0991e 100644 --- a/iseq.c +++ b/iseq.c @@ -1388,18 +1388,30 @@ rb_iseq_remove_coverage_all(void) static void iseqw_mark(void *ptr) { - rb_gc_mark((VALUE)ptr); + rb_gc_mark_movable(*(VALUE *)ptr); } static size_t iseqw_memsize(const void *ptr) { - return rb_iseq_memsize((const rb_iseq_t *)ptr); + return rb_iseq_memsize(*(const rb_iseq_t **)ptr); +} + +static void +iseqw_ref_update(void *ptr) +{ + VALUE *vptr = ptr; + *vptr = rb_gc_location(*vptr); } static const rb_data_type_t iseqw_data_type = { "T_IMEMO/iseq", - {iseqw_mark, NULL, iseqw_memsize,}, + { + iseqw_mark, + RUBY_TYPED_DEFAULT_FREE, + iseqw_memsize, + iseqw_ref_update, + }, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED }; @@ -1410,11 +1422,9 @@ iseqw_new(const rb_iseq_t *iseq) return iseq->wrapper; } else { - union { const rb_iseq_t *in; void *out; } deconst; - VALUE obj; - deconst.in = iseq; - obj = TypedData_Wrap_Struct(rb_cISeq, &iseqw_data_type, deconst.out); - RB_OBJ_WRITTEN(obj, Qundef, iseq); + rb_iseq_t **ptr; + VALUE obj = TypedData_Make_Struct(rb_cISeq, rb_iseq_t *, &iseqw_data_type, ptr); + RB_OBJ_WRITE(obj, ptr, iseq); FL_SET_RAW(obj, RUBY_FL_SHAREABLE); @@ -1740,7 +1750,9 @@ iseqw_s_compile_option_get(VALUE self) static const rb_iseq_t * iseqw_check(VALUE iseqw) { - rb_iseq_t *iseq = DATA_PTR(iseqw); + rb_iseq_t **iseq_ptr; + TypedData_Get_Struct(iseqw, rb_iseq_t *, &iseqw_data_type, iseq_ptr); + rb_iseq_t *iseq = *iseq_ptr; if (!ISEQ_BODY(iseq)) { rb_ibf_load_iseq_complete(iseq); diff --git a/lib/bundled_gems.rb b/lib/bundled_gems.rb index 55286725c0fb45..a8ea9fe211c2ee 100644 --- a/lib/bundled_gems.rb +++ b/lib/bundled_gems.rb @@ -95,8 +95,10 @@ def self.find_gem(path) end def self.warning?(name, specs: nil) - feature = File.path(name) # name can be a feature name or a file path with String or Pathname - name = feature.tr("/", "-") + # 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("/", "-") name.sub!(LIBEXT, "") return if specs.include?(name) _t, path = $:.resolve_feature_path(feature) @@ -109,12 +111,7 @@ def self.warning?(name, specs: nil) else return end - # Warning feature is not working correctly with Bootsnap. - # caller_locations returns: - # lib/ruby/3.3.0+0/bundled_gems.rb:65:in `block (2 levels) in replace_require' - # $GEM_HOME/gems/bootsnap-1.17.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'" - # ... - return if caller_locations(2).find {|c| c&.path.match?(/bootsnap/) } + return if WARNED[name] WARNED[name] = true if gem == true @@ -134,11 +131,29 @@ def self.build_message(gem) if defined?(Bundler) msg += " Add #{gem} to your Gemfile or gemspec." + # We detect the gem name from caller_locations. We need to skip 2 frames like: # lib/ruby/3.3.0+0/bundled_gems.rb:90:in `warning?'", # lib/ruby/3.3.0+0/bundler/rubygems_integration.rb:247:in `block (2 levels) in replace_require'", - location = caller_locations(3,1)[0]&.path - if File.file?(location) && !location.start_with?(Gem::BUNDLED_GEMS::LIBDIR) + # + # Additionally, we need to skip Bootsnap and Zeitwerk if present, these + # gems decorate Kernel#require, so they are not really the ones issuing + # the require call users should be warned about. Those are upwards. + frames_to_skip = 2 + location = nil + Thread.each_caller_location do |cl| + if frames_to_skip >= 1 + frames_to_skip -= 1 + next + end + + if cl.base_label != "require" + location = cl.path + break + end + end + + if location && File.file?(location) && !location.start_with?(Gem::BUNDLED_GEMS::LIBDIR) caller_gem = nil Gem.path.each do |path| if location =~ %r{#{path}/gems/([\w\-\.]+)} diff --git a/lib/bundler/plugin/installer.rb b/lib/bundler/plugin/installer.rb index 7ae56440fbbf2f..7267f58f5d5ea9 100644 --- a/lib/bundler/plugin/installer.rb +++ b/lib/bundler/plugin/installer.rb @@ -43,11 +43,24 @@ def check_sources_consistency!(options) if options.key?(:git) && options.key?(:local_git) raise InvalidOption, "Remote and local plugin git sources can't be both specified" end + # back-compat; local_git is an alias for git if options.key?(:local_git) Bundler::SharedHelpers.major_deprecation(2, "--local_git is deprecated, use --git") options[:git] = options.delete(:local_git) end + + if (options.keys & [:source, :git]).length > 1 + raise InvalidOption, "Only one of --source, or --git may be specified" + end + + if (options.key?(:branch) || options.key?(:ref)) && !options.key?(:git) + raise InvalidOption, "--#{options.key?(:branch) ? "branch" : "ref"} can only be used with git sources" + end + + if options.key?(:branch) && options.key?(:ref) + raise InvalidOption, "--branch and --ref can't be both specified" + end end def install_git(names, version, options) diff --git a/lib/bundler/self_manager.rb b/lib/bundler/self_manager.rb index 5accda4bcbaccc..bfd000b1a01da2 100644 --- a/lib/bundler/self_manager.rb +++ b/lib/bundler/self_manager.rb @@ -113,7 +113,7 @@ def resolve_update_version_from(target) end def local_specs - @local_specs ||= Bundler::Source::Rubygems.new("allow_local" => true).specs.select {|spec| spec.name == "bundler" } + @local_specs ||= Bundler::Source::Rubygems.new("allow_local" => true, "allow_cached" => true).specs.select {|spec| spec.name == "bundler" } end def remote_specs diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 861aa8bbebb687..04cfc0a85092eb 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -17,7 +17,7 @@ def initialize(options = {}) @remotes = [] @dependency_names = [] @allow_remote = false - @allow_cached = false + @allow_cached = options["allow_cached"] || false @allow_local = options["allow_local"] || false @checksum_store = Checksum::Store.new @@ -133,7 +133,7 @@ def specs # sources, and large_idx.merge! small_idx is way faster than # small_idx.merge! large_idx. index = @allow_remote ? remote_specs.dup : Index.new - index.merge!(cached_specs) if @allow_cached || @allow_remote + index.merge!(cached_specs) if @allow_cached index.merge!(installed_specs) if @allow_local index end diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index 4419695b7ff1ab..d85e1c1c013806 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -9,7 +9,7 @@ class SourceList :metadata_source def global_rubygems_source - @global_rubygems_source ||= rubygems_aggregate_class.new("allow_local" => true) + @global_rubygems_source ||= rubygems_aggregate_class.new("allow_local" => true, "allow_cached" => true) end def initialize @@ -174,7 +174,7 @@ def global_replacement_source(replacement_sources) replacement_source = replacement_sources.find {|s| s == global_rubygems_source } return global_rubygems_source unless replacement_source - replacement_source.local! + replacement_source.cached! replacement_source end diff --git a/lib/irb.rb b/lib/irb.rb index 8e27aff0b18dff..c7d36e74456476 100644 --- a/lib/irb.rb +++ b/lib/irb.rb @@ -145,7 +145,6 @@ # * The value of variable `$XDG_CONFIG_HOME/irb/irbrc`, if defined. # * File `$HOME/.irbrc`, if it exists. # * File `$HOME/.config/irb/irbrc`, if it exists. -# * File `.config/irb/irbrc` in the current directory, if it exists. # * File `.irbrc` in the current directory, if it exists. # * File `irb.rc` in the current directory, if it exists. # * File `_irbrc` in the current directory, if it exists. diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb index c1998309283fc3..e5adb350e8ceef 100644 --- a/lib/irb/input-method.rb +++ b/lib/irb/input-method.rb @@ -308,6 +308,20 @@ def retrieve_doc_namespace(matched) @completor.doc_namespace(preposing, matched, postposing, bind: bind) end + def rdoc_ri_driver + return @rdoc_ri_driver if defined?(@rdoc_ri_driver) + + begin + require 'rdoc' + rescue LoadError + @rdoc_ri_driver = nil + else + options = {} + options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty? + @rdoc_ri_driver = RDoc::RI::Driver.new(options) + end + end + def show_doc_dialog_proc input_method = self # self is changed in the lambda below. ->() { @@ -331,9 +345,7 @@ def show_doc_dialog_proc show_easter_egg = name&.match?(/\ARubyVM/) && !ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER'] - options = {} - options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty? - driver = RDoc::RI::Driver.new(options) + driver = input_method.rdoc_ri_driver if key.match?(dialog.name) if show_easter_egg @@ -421,12 +433,9 @@ def show_doc_dialog_proc } end - def display_document(matched, driver: nil) - begin - require 'rdoc' - rescue LoadError - return - end + def display_document(matched) + driver = rdoc_ri_driver + return unless driver if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER'] IRB.__send__(:easter_egg) @@ -436,7 +445,6 @@ def display_document(matched, driver: nil) namespace = retrieve_doc_namespace(matched) return unless namespace - driver ||= RDoc::RI::Driver.new if namespace.is_a?(Array) out = RDoc::Markup::Document.new namespace.each do |m| diff --git a/lib/prism/translation/parser.rb b/lib/prism/translation/parser.rb index 8df71646882d75..0d11b8f5668cca 100644 --- a/lib/prism/translation/parser.rb +++ b/lib/prism/translation/parser.rb @@ -173,6 +173,8 @@ def error_diagnostic(error, offset_cache) Diagnostic.new(:error, :duplicate_argument, {}, diagnostic_location, []) when :parameter_numbered_reserved Diagnostic.new(:error, :reserved_for_numparam, { name: location.slice }, diagnostic_location, []) + when :regexp_unknown_options + Diagnostic.new(:error, :regexp_options, { options: location.slice[1..] }, diagnostic_location, []) when :singleton_for_literals Diagnostic.new(:error, :singleton_literal, {}, diagnostic_location, []) when :string_literal_eof diff --git a/lib/prism/translation/ruby_parser.rb b/lib/prism/translation/ruby_parser.rb index 108e6c6928c5cd..5c59fe31810562 100644 --- a/lib/prism/translation/ruby_parser.rb +++ b/lib/prism/translation/ruby_parser.rb @@ -192,19 +192,19 @@ def visit_block_parameters_node(node) if node.opening == "(" result.line = node.opening_loc.start_line - result.max_line = node.closing_loc.end_line + result.line_max = node.closing_loc.end_line shadow_loc = false end if node.locals.any? shadow = s(node, :shadow).concat(visit_all(node.locals)) shadow.line = node.locals.first.location.start_line - shadow.max_line = node.locals.last.location.end_line + shadow.line_max = node.locals.last.location.end_line result << shadow if shadow_loc result.line = shadow.line - result.max_line = shadow.max_line + result.line_max = shadow.line_max end end @@ -1412,7 +1412,7 @@ def visit_x_string_node(node) if node.heredoc? result.line = node.content_loc.start_line - result.max_line = node.content_loc.end_line + result.line_max = node.content_loc.end_line end result @@ -1439,7 +1439,7 @@ def s(node, *arguments) result = Sexp.new(*arguments) result.file = file result.line = node.location.start_line - result.max_line = node.location.end_line + result.line_max = node.location.end_line result end diff --git a/lib/rdoc/store.rb b/lib/rdoc/store.rb index fe749edc1cea9a..cd27d47dd1dfdc 100644 --- a/lib/rdoc/store.rb +++ b/lib/rdoc/store.rb @@ -559,9 +559,7 @@ def load_all def load_cache #orig_enc = @encoding - File.open cache_path, 'rb' do |io| - @cache = Marshal.load io - end + @cache = marshal_load(cache_path) load_enc = @cache[:encoding] @@ -618,9 +616,7 @@ def load_class klass_name def load_class_data klass_name file = class_file klass_name - File.open file, 'rb' do |io| - Marshal.load io - end + marshal_load(file) rescue Errno::ENOENT => e error = MissingFileError.new(self, file, klass_name) error.set_backtrace e.backtrace @@ -633,14 +629,10 @@ def load_class_data klass_name def load_method klass_name, method_name file = method_file klass_name, method_name - File.open file, 'rb' do |io| - obj = Marshal.load io - obj.store = self - obj.parent = - find_class_or_module(klass_name) || load_class(klass_name) unless - obj.parent - obj - end + obj = marshal_load(file) + obj.store = self + obj.parent ||= find_class_or_module(klass_name) || load_class(klass_name) + obj rescue Errno::ENOENT => e error = MissingFileError.new(self, file, klass_name + method_name) error.set_backtrace e.backtrace @@ -653,11 +645,9 @@ def load_method klass_name, method_name def load_page page_name file = page_file page_name - File.open file, 'rb' do |io| - obj = Marshal.load io - obj.store = self - obj - end + obj = marshal_load(file) + obj.store = self + obj rescue Errno::ENOENT => e error = MissingFileError.new(self, file, page_name) error.set_backtrace e.backtrace @@ -979,4 +969,21 @@ def unique_modules @unique_modules end + private + def marshal_load(file) + File.open(file, 'rb') {|io| Marshal.load(io, MarshalFilter)} + end + + MarshalFilter = proc do |obj| + case obj + when true, false, nil, Array, Class, Encoding, Hash, Integer, String, Symbol, RDoc::Text + else + unless obj.class.name.start_with?("RDoc::") + raise TypeError, "not permitted class: #{obj.class.name}" + end + end + obj + end + private_constant :MarshalFilter + end diff --git a/lib/rdoc/version.rb b/lib/rdoc/version.rb index 04dfaebf746d87..87842d9847a9ee 100644 --- a/lib/rdoc/version.rb +++ b/lib/rdoc/version.rb @@ -5,6 +5,6 @@ module RDoc ## # RDoc version you are using - VERSION = '6.6.2' + VERSION = '6.6.3.1' end diff --git a/lib/reline.rb b/lib/reline.rb index 713d1a8b60c78c..f3fd28b627736a 100644 --- a/lib/reline.rb +++ b/lib/reline.rb @@ -331,8 +331,10 @@ def readline(prompt = '', add_hist = false) line_editor.auto_indent_proc = auto_indent_proc line_editor.dig_perfect_match_proc = dig_perfect_match_proc pre_input_hook&.call - @dialog_proc_list.each_pair do |name_sym, d| - line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context) + unless Reline::IOGate == Reline::GeneralIO + @dialog_proc_list.each_pair do |name_sym, d| + line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context) + end end unless config.test_mode diff --git a/lib/reline/ansi.rb b/lib/reline/ansi.rb index c2e5075ea8b5b4..2d7c759ea25f54 100644 --- a/lib/reline/ansi.rb +++ b/lib/reline/ansi.rb @@ -3,6 +3,8 @@ require_relative 'terminfo' class Reline::ANSI + RESET_COLOR = "\e[0m" + CAPNAME_KEY_BINDINGS = { 'khome' => :ed_move_to_beg, 'kend' => :ed_move_to_end, diff --git a/lib/reline/general_io.rb b/lib/reline/general_io.rb index b830eb39a01203..0ac1c6c56d40bc 100644 --- a/lib/reline/general_io.rb +++ b/lib/reline/general_io.rb @@ -1,6 +1,8 @@ require 'io/wait' class Reline::GeneralIO + RESET_COLOR = '' # Do not send color reset sequence + def self.reset(encoding: nil) @@pasting = false if encoding @@ -100,14 +102,6 @@ def self.in_pasting? @@pasting end - def self.start_pasting - @@pasting = true - end - - def self.finish_pasting - @@pasting = false - end - def self.prep end diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb index 2d30f69d2311b6..d202ba02d27a76 100644 --- a/lib/reline/line_editor.rb +++ b/lib/reline/line_editor.rb @@ -85,7 +85,7 @@ def set_pasting_state(in_pasting) end end - private def check_multiline_prompt(buffer) + private def check_multiline_prompt(buffer, mode_string) if @vi_arg prompt = "(arg: #{@vi_arg}) " elsif @searching_prompt @@ -97,7 +97,6 @@ def set_pasting_state(in_pasting) prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") } prompt_list.map!{ prompt } if @vi_arg or @searching_prompt prompt_list = [prompt] if prompt_list.empty? - mode_string = check_mode_string prompt_list = prompt_list.map{ |pr| mode_string + pr } if mode_string prompt = prompt_list[@line_index] prompt = prompt_list[0] if prompt.nil? @@ -109,7 +108,6 @@ def set_pasting_state(in_pasting) end prompt_list else - mode_string = check_mode_string prompt = mode_string + prompt if mode_string [prompt] * buffer.size end @@ -153,7 +151,7 @@ def resize scroll_into_view Reline::IOGate.move_cursor_up @rendered_screen.cursor_y @rendered_screen.base_y = Reline::IOGate.cursor_pos.y - @rendered_screen.lines = nil + @rendered_screen.lines = [] @rendered_screen.cursor_y = 0 render_differential end @@ -164,7 +162,7 @@ def set_signal_handlers scrolldown = render_differential Reline::IOGate.scroll_down scrolldown Reline::IOGate.move_cursor_column 0 - @rendered_screen.lines = nil + @rendered_screen.lines = [] @rendered_screen.cursor_y = 0 case @old_trap when 'DEFAULT', 'SYSTEM_DEFAULT' @@ -217,7 +215,7 @@ def reset_variables(prompt = '', encoding:) @dialogs = [] @resized = false @cache = {} - @rendered_screen = RenderedScreen.new(base_y: 0, lines: nil, cursor_y: 0) + @rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0) reset_line end @@ -319,8 +317,8 @@ def modified_lines end def prompt_list - with_cache(__method__, whole_lines, @vi_arg, @searching_prompt) do |lines| - check_multiline_prompt(lines) + with_cache(__method__, whole_lines, check_mode_string, @vi_arg, @searching_prompt) do |lines, mode_string| + check_multiline_prompt(lines, mode_string) end end @@ -372,12 +370,12 @@ def render_line_differential(old_items, new_items) # do nothing elsif level == :blank Reline::IOGate.move_cursor_column base_x - @output.write "\e[0m#{' ' * width}" + @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 - @output.write "\e[0m#{content}\e[0m" + @output.write "#{Reline::IOGate::RESET_COLOR}#{content}#{Reline::IOGate::RESET_COLOR}" end base_x += width end @@ -421,7 +419,7 @@ def clear_rendered_lines Reline::IOGate.move_cursor_up @rendered_screen.cursor_y Reline::IOGate.move_cursor_column 0 - num_lines = @rendered_screen.lines&.size + num_lines = @rendered_screen.lines.size return unless num_lines && num_lines >= 1 Reline::IOGate.move_cursor_down num_lines - 1 @@ -430,7 +428,7 @@ def clear_rendered_lines Reline::IOGate.move_cursor_up 1 end Reline::IOGate.erase_after_cursor - @rendered_screen.lines = nil + @rendered_screen.lines = [] @rendered_screen.cursor_y = 0 end @@ -455,7 +453,7 @@ def print_nomultiline_prompt(prompt) def render_differential wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position - rendered_lines = @rendered_screen.lines || [] + 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]] end @@ -528,7 +526,7 @@ def handle_cleared @cleared = false Reline::IOGate.clear_screen @screen_size = Reline::IOGate.get_screen_size - @rendered_screen.lines = nil + @rendered_screen.lines = [] @rendered_screen.base_y = 0 @rendered_screen.cursor_y = 0 end diff --git a/lib/reline/version.rb b/lib/reline/version.rb index 8f21e6a9cfb2d4..06bb3acc8454e9 100644 --- a/lib/reline/version.rb +++ b/lib/reline/version.rb @@ -1,3 +1,3 @@ module Reline - VERSION = '0.5.0.pre.1' + VERSION = '0.5.0' end diff --git a/lib/reline/windows.rb b/lib/reline/windows.rb index a22331fae52ebb..28f28e15ccd119 100644 --- a/lib/reline/windows.rb +++ b/lib/reline/windows.rb @@ -1,6 +1,8 @@ require 'fiddle/import' class Reline::Windows + RESET_COLOR = "\e[0m" + def self.encoding Encoding::UTF_8 end diff --git a/lib/rubygems/exceptions.rb b/lib/rubygems/exceptions.rb index 65caaab8b1f3c0..0308b4687f9f49 100644 --- a/lib/rubygems/exceptions.rb +++ b/lib/rubygems/exceptions.rb @@ -292,9 +292,3 @@ def version @dependency.requirement end end - -## -# Backwards compatible typo'd exception class for early RubyGems 2.0.x - -Gem::UnsatisfiableDepedencyError = Gem::UnsatisfiableDependencyError # :nodoc: -Gem.deprecate_constant :UnsatisfiableDepedencyError diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index 387e40ffd753bb..72a179da376d87 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -454,7 +454,7 @@ def extract_tar_gz(io, destination_dir, pattern = "*") # :nodoc: if entry.file? File.open(destination, "wb") {|out| copy_stream(entry, out) } - FileUtils.chmod file_mode(entry.header.mode), destination + FileUtils.chmod file_mode(entry.header.mode) & ~File.umask, destination end verbose destination diff --git a/misc/lldb_rb/utils.py b/misc/lldb_rb/utils.py index a321426234befd..054c206cef02f3 100644 --- a/misc/lldb_rb/utils.py +++ b/misc/lldb_rb/utils.py @@ -119,6 +119,10 @@ def inspect(self, val): self.result.write('T_STRING: %s' % flaginfo) tRString = self.target.FindFirstType("struct RString").GetPointerType() + chilled = self.ruby_globals["RUBY_FL_USER3"] + if (rval.flags & chilled) != 0: + self.result.write("[CHILLED] ") + rb_enc_mask = self.ruby_globals["RUBY_ENCODING_MASK"] rb_enc_shift = self.ruby_globals["RUBY_ENCODING_SHIFT"] encidx = ((rval.flags & rb_enc_mask) >> rb_enc_shift) diff --git a/parse.y b/parse.y index a9db3d4e6eb181..28b03f8cd149b8 100644 --- a/parse.y +++ b/parse.y @@ -14068,13 +14068,13 @@ mark_lvar_used(struct parser_params *p, NODE *rhs) } static NODE * -const_decl_path(struct parser_params *p, NODE **dest) +const_decl_path(struct parser_params *p, NODE *dest) { - NODE *n = *dest; - if (!nd_type_p(n, NODE_CALL)) { - const YYLTYPE *loc = &n->nd_loc; - VALUE path = rb_node_const_decl_val(n); - *dest = n = NEW_LIT(path, loc); + NODE *n = dest; + if (!nd_type_p(dest, NODE_CALL)) { + const YYLTYPE *loc = &dest->nd_loc; + VALUE path = rb_node_const_decl_val(dest); + n = NEW_LIT(path, loc); RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(n)->nd_lit); } return n; @@ -14096,7 +14096,7 @@ make_shareable_node(struct parser_params *p, NODE *value, bool copy, const YYLTY } static NODE * -ensure_shareable_node(struct parser_params *p, NODE **dest, NODE *value, const YYLTYPE *loc) +ensure_shareable_node(struct parser_params *p, NODE *dest, NODE *value, const YYLTYPE *loc) { NODE *fcore = NEW_LIT(rb_mRubyVMFrozenCore, loc); NODE *args = NEW_LIST(value, loc); @@ -14147,7 +14147,7 @@ shareable_literal_value(struct parser_params *p, NODE *node) static NODE * shareable_literal_constant(struct parser_params *p, enum shareability shareable, - NODE **dest, NODE *value, const YYLTYPE *loc, size_t level) + NODE *dest, NODE *value, const YYLTYPE *loc, size_t level) { # define shareable_literal_constant_next(n) \ shareable_literal_constant(p, shareable, dest, (n), &(n)->nd_loc, level+1) @@ -14297,7 +14297,7 @@ shareable_constant_value(struct parser_params *p, enum shareability shareable, case shareable_literal: { - NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0); + NODE *lit = shareable_literal_constant(p, shareable, lhs, value, loc, 0); if (lit) return lit; return value; } @@ -14306,7 +14306,7 @@ shareable_constant_value(struct parser_params *p, enum shareability shareable, case shareable_copy: case shareable_everything: { - NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0); + NODE *lit = shareable_literal_constant(p, shareable, lhs, value, loc, 0); if (lit) return lit; return make_shareable_node(p, value, shareable == shareable_copy, loc); } @@ -16613,6 +16613,16 @@ rb_ruby_ripper_lex_state_name(struct parser_params *p, int state) return rb_parser_lex_state_name(p, (enum lex_state_e)state); } +#ifdef UNIVERSAL_PARSER +rb_parser_t * +rb_ripper_parser_params_allocate(const rb_parser_config_t *config) +{ + rb_parser_t *p = (rb_parser_t *)config->calloc(1, sizeof(rb_parser_t)); + p->config = config; + return p; +} +#endif + struct parser_params* rb_ruby_ripper_parser_allocate(void) { diff --git a/prism/config.yml b/prism/config.yml index 269bfa73ec5efa..d9e39460d12f2c 100644 --- a/prism/config.yml +++ b/prism/config.yml @@ -199,6 +199,7 @@ errors: - REGEXP_INVALID_UNICODE_RANGE - REGEXP_NON_ESCAPED_MBC - REGEXP_TERM + - REGEXP_UNKNOWN_OPTIONS - REGEXP_UTF8_CHAR_NON_UTF8_REGEXP - RESCUE_EXPRESSION - RESCUE_MODIFIER_VALUE diff --git a/prism/encoding.c b/prism/encoding.c index dc63cccc2db2a4..a4aeed104f89b9 100644 --- a/prism/encoding.c +++ b/prism/encoding.c @@ -2358,6 +2358,8 @@ pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n) { } } +#ifndef PRISM_ENCODING_EXCLUDE_FULL + static pm_unicode_codepoint_t pm_cesu_8_codepoint(const uint8_t *b, ptrdiff_t n, size_t *width) { if (b[0] < 0x80) { @@ -2452,6 +2454,8 @@ pm_encoding_cesu_8_isupper_char(const uint8_t *b, ptrdiff_t n) { } } +#endif + #undef UNICODE_ALPHA_CODEPOINTS_LENGTH #undef UNICODE_ALNUM_CODEPOINTS_LENGTH #undef UNICODE_ISUPPER_CODEPOINTS_LENGTH @@ -2480,6 +2484,8 @@ static const uint8_t pm_encoding_ascii_table[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx }; +#ifndef PRISM_ENCODING_EXCLUDE_FULL + /** * Each element of the following table contains a bitfield that indicates a * piece of information about the corresponding CP850 character. @@ -3918,6 +3924,7 @@ PRISM_ENCODING_TABLE(windows_1258) PRISM_ENCODING_TABLE(windows_874) #undef PRISM_ENCODING_TABLE +#endif /** * Returns the size of the next character in the ASCII encoding. This basically @@ -3976,22 +3983,129 @@ pm_encoding_ascii_isupper_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_ } /** - * Certain encodings are equivalent to ASCII below 0x80, so it works for our - * purposes to have a function here that first checks the bounds and then falls - * back to checking the ASCII lookup table. + * For a lot of encodings the default is that they are a single byte long no + * matter what the codepoint, so this function is shared between them. + */ +static size_t +pm_encoding_single_char_width(PRISM_ATTRIBUTE_UNUSED const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) { + return 1; +} + +/** + * Returns the size of the next character in the EUC-JP encoding, or 0 if a + * character cannot be decoded from the given bytes. + */ +static size_t +pm_encoding_euc_jp_char_width(const uint8_t *b, ptrdiff_t n) { + // These are the single byte characters. + if (*b < 0x80) { + return 1; + } + + // These are the double byte characters. + if ((n > 1) && ((b[0] == 0x8E) || (b[0] >= 0xA1 && b[0] <= 0xFE)) && (b[1] >= 0xA1 && b[1] <= 0xFE)) { + return 2; + } + + // These are the triple byte characters. + if ((n > 2) && (b[0] == 0x8F) && (b[1] >= 0xA1 && b[2] <= 0xFE) && (b[2] >= 0xA1 && b[2] <= 0xFE)) { + return 3; + } + + return 0; +} + +/** + * Returns the size of the next character in the EUC-JP encoding if it is an + * uppercase character. */ static bool -pm_encoding_ascii_isupper_char_7bit(const uint8_t *b, ptrdiff_t n) { - return (*b < 0x80) && pm_encoding_ascii_isupper_char(b, n); +pm_encoding_euc_jp_isupper_char(const uint8_t *b, ptrdiff_t n) { + size_t width = pm_encoding_euc_jp_char_width(b, n); + + if (width == 1) { + return pm_encoding_ascii_isupper_char(b, n); + } else if (width == 2) { + return ( + (b[0] == 0xA3 && b[1] >= 0xC1 && b[1] <= 0xDA) || + (b[0] == 0xA6 && b[1] >= 0xA1 && b[1] <= 0xB8) || + (b[0] == 0xA7 && b[1] >= 0xA1 && b[1] <= 0xC1) + ); + } else { + return false; + } } /** - * For a lot of encodings the default is that they are a single byte long no - * matter what the codepoint, so this function is shared between them. + * Returns the size of the next character in the Shift_JIS encoding, or 0 if a + * character cannot be decoded from the given bytes. */ static size_t -pm_encoding_single_char_width(PRISM_ATTRIBUTE_UNUSED const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) { - return 1; +pm_encoding_shift_jis_char_width(const uint8_t *b, ptrdiff_t n) { + // These are the single byte characters. + if (b[0] < 0x80 || (b[0] >= 0xA1 && b[0] <= 0xDF)) { + return 1; + } + + // These are the double byte characters. + if ((n > 1) && ((b[0] >= 0x81 && b[0] <= 0x9F) || (b[0] >= 0xE0 && b[0] <= 0xFC)) && (b[1] >= 0x40 && b[1] <= 0xFC && b[1] != 0x7F)) { + return 2; + } + + return 0; +} + +/** + * Returns the size of the next character in the Shift_JIS encoding if it is an + * alphanumeric character. + */ +static size_t +pm_encoding_shift_jis_alnum_char(const uint8_t *b, ptrdiff_t n) { + size_t width = pm_encoding_shift_jis_char_width(b, n); + return width == 1 ? ((b[0] >= 0x80) || pm_encoding_ascii_alnum_char(b, n)) : width; +} + +/** + * Returns the size of the next character in the Shift_JIS encoding if it is an + * alphabetical character. + */ +static size_t +pm_encoding_shift_jis_alpha_char(const uint8_t *b, ptrdiff_t n) { + size_t width = pm_encoding_shift_jis_char_width(b, n); + return width == 1 ? ((b[0] >= 0x80) || pm_encoding_ascii_alpha_char(b, n)) : width; +} + +/** + * Returns the size of the next character in the Shift_JIS encoding if it is an + * uppercase character. + */ +static bool +pm_encoding_shift_jis_isupper_char(const uint8_t *b, ptrdiff_t n) { + size_t width = pm_encoding_shift_jis_char_width(b, n); + + if (width == 1) { + return pm_encoding_ascii_isupper_char(b, n); + } else if (width == 2) { + return ( + ((b[0] == 0x82) && (b[1] >= 0x60 && b[1] <= 0x79)) || + ((b[0] == 0x83) && (b[1] >= 0x9F && b[1] <= 0xB6)) || + ((b[0] == 0x84) && (b[1] >= 0x40 && b[1] <= 0x60)) + ); + } else { + return width; + } +} + +#ifndef PRISM_ENCODING_EXCLUDE_FULL + +/** + * Certain encodings are equivalent to ASCII below 0x80, so it works for our + * purposes to have a function here that first checks the bounds and then falls + * back to checking the ASCII lookup table. + */ +static bool +pm_encoding_ascii_isupper_char_7bit(const uint8_t *b, ptrdiff_t n) { + return (*b < 0x80) && pm_encoding_ascii_isupper_char(b, n); } /** @@ -4075,51 +4189,6 @@ pm_encoding_emacs_mule_char_width(const uint8_t *b, ptrdiff_t n) { return 0; } -/** - * Returns the size of the next character in the EUC-JP encoding, or 0 if a - * character cannot be decoded from the given bytes. - */ -static size_t -pm_encoding_euc_jp_char_width(const uint8_t *b, ptrdiff_t n) { - // These are the single byte characters. - if (*b < 0x80) { - return 1; - } - - // These are the double byte characters. - if ((n > 1) && ((b[0] == 0x8E) || (b[0] >= 0xA1 && b[0] <= 0xFE)) && (b[1] >= 0xA1 && b[1] <= 0xFE)) { - return 2; - } - - // These are the triple byte characters. - if ((n > 2) && (b[0] == 0x8F) && (b[1] >= 0xA1 && b[2] <= 0xFE) && (b[2] >= 0xA1 && b[2] <= 0xFE)) { - return 3; - } - - return 0; -} - -/** - * Returns the size of the next character in the EUC-JP encoding if it is an - * uppercase character. - */ -static bool -pm_encoding_euc_jp_isupper_char(const uint8_t *b, ptrdiff_t n) { - size_t width = pm_encoding_euc_jp_char_width(b, n); - - if (width == 1) { - return pm_encoding_ascii_isupper_char(b, n); - } else if (width == 2) { - return ( - (b[0] == 0xA3 && b[1] >= 0xC1 && b[1] <= 0xDA) || - (b[0] == 0xA6 && b[1] >= 0xA1 && b[1] <= 0xB8) || - (b[0] == 0xA7 && b[1] >= 0xA1 && b[1] <= 0xC1) - ); - } else { - return false; - } -} - /** * Returns the size of the next character in the EUC-KR encoding, or 0 if a * character cannot be decoded from the given bytes. @@ -4218,65 +4287,7 @@ pm_encoding_gbk_char_width(const uint8_t *b, ptrdiff_t n) { return 0; } -/** - * Returns the size of the next character in the Shift_JIS encoding, or 0 if a - * character cannot be decoded from the given bytes. - */ -static size_t -pm_encoding_shift_jis_char_width(const uint8_t *b, ptrdiff_t n) { - // These are the single byte characters. - if (b[0] < 0x80 || (b[0] >= 0xA1 && b[0] <= 0xDF)) { - return 1; - } - - // These are the double byte characters. - if ((n > 1) && ((b[0] >= 0x81 && b[0] <= 0x9F) || (b[0] >= 0xE0 && b[0] <= 0xFC)) && (b[1] >= 0x40 && b[1] <= 0xFC && b[1] != 0x7F)) { - return 2; - } - - return 0; -} - -/** - * Returns the size of the next character in the Shift_JIS encoding if it is an - * alphanumeric character. - */ -static size_t -pm_encoding_shift_jis_alnum_char(const uint8_t *b, ptrdiff_t n) { - size_t width = pm_encoding_shift_jis_char_width(b, n); - return width == 1 ? ((b[0] >= 0x80) || pm_encoding_ascii_alnum_char(b, n)) : width; -} - -/** - * Returns the size of the next character in the Shift_JIS encoding if it is an - * alphabetical character. - */ -static size_t -pm_encoding_shift_jis_alpha_char(const uint8_t *b, ptrdiff_t n) { - size_t width = pm_encoding_shift_jis_char_width(b, n); - return width == 1 ? ((b[0] >= 0x80) || pm_encoding_ascii_alpha_char(b, n)) : width; -} - -/** - * Returns the size of the next character in the Shift_JIS encoding if it is an - * uppercase character. - */ -static bool -pm_encoding_shift_jis_isupper_char(const uint8_t *b, ptrdiff_t n) { - size_t width = pm_encoding_shift_jis_char_width(b, n); - - if (width == 1) { - return pm_encoding_ascii_isupper_char(b, n); - } else if (width == 2) { - return ( - ((b[0] == 0x82) && (b[1] >= 0x60 && b[1] <= 0x79)) || - ((b[0] == 0x83) && (b[1] >= 0x9F && b[1] <= 0xB6)) || - ((b[0] == 0x84) && (b[1] >= 0x40 && b[1] <= 0x60)) - ); - } else { - return width; - } -} +#endif /** * This is the table of all of the encodings that prism supports. @@ -4290,6 +4301,14 @@ const pm_encoding_t pm_encodings[] = { .isupper_char = pm_encoding_utf_8_isupper_char, .multibyte = true }, + [PM_ENCODING_US_ASCII] = { + .name = "US-ASCII", + .char_width = pm_encoding_ascii_char_width, + .alnum_char = pm_encoding_ascii_alnum_char, + .alpha_char = pm_encoding_ascii_alpha_char, + .isupper_char = pm_encoding_ascii_isupper_char, + .multibyte = false + }, [PM_ENCODING_ASCII_8BIT] = { .name = "ASCII-8BIT", .char_width = pm_encoding_single_char_width, @@ -4298,6 +4317,24 @@ const pm_encoding_t pm_encodings[] = { .isupper_char = pm_encoding_ascii_isupper_char, .multibyte = false }, + [PM_ENCODING_EUC_JP] = { + .name = "EUC-JP", + .char_width = pm_encoding_euc_jp_char_width, + .alnum_char = pm_encoding_ascii_alnum_char_7bit, + .alpha_char = pm_encoding_ascii_alpha_char_7bit, + .isupper_char = pm_encoding_euc_jp_isupper_char, + .multibyte = true + }, + [PM_ENCODING_WINDOWS_31J] = { + .name = "Windows-31J", + .char_width = pm_encoding_shift_jis_char_width, + .alnum_char = pm_encoding_shift_jis_alnum_char, + .alpha_char = pm_encoding_shift_jis_alpha_char, + .isupper_char = pm_encoding_shift_jis_isupper_char, + .multibyte = true + }, + +#ifndef PRISM_ENCODING_EXCLUDE_FULL [PM_ENCODING_BIG5] = { .name = "Big5", .char_width = pm_encoding_big5_char_width, @@ -4394,14 +4431,6 @@ const pm_encoding_t pm_encodings[] = { .isupper_char = pm_encoding_ascii_isupper_char_7bit, .multibyte = true }, - [PM_ENCODING_EUC_JP] = { - .name = "EUC-JP", - .char_width = pm_encoding_euc_jp_char_width, - .alnum_char = pm_encoding_ascii_alnum_char_7bit, - .alpha_char = pm_encoding_ascii_alpha_char_7bit, - .isupper_char = pm_encoding_euc_jp_isupper_char, - .multibyte = true - }, [PM_ENCODING_EUC_JP_MS] = { .name = "eucJP-ms", .char_width = pm_encoding_euc_jp_char_width, @@ -4874,14 +4903,6 @@ const pm_encoding_t pm_encodings[] = { .isupper_char = pm_encoding_tis_620_isupper_char, .multibyte = false }, - [PM_ENCODING_US_ASCII] = { - .name = "US-ASCII", - .char_width = pm_encoding_ascii_char_width, - .alnum_char = pm_encoding_ascii_alnum_char, - .alpha_char = pm_encoding_ascii_alpha_char, - .isupper_char = pm_encoding_ascii_isupper_char, - .multibyte = false - }, [PM_ENCODING_UTF8_MAC] = { .name = "UTF8-MAC", .char_width = pm_encoding_utf_8_char_width, @@ -4986,14 +5007,6 @@ const pm_encoding_t pm_encodings[] = { .isupper_char = pm_encoding_windows_1258_isupper_char, .multibyte = false }, - [PM_ENCODING_WINDOWS_31J] = { - .name = "Windows-31J", - .char_width = pm_encoding_shift_jis_char_width, - .alnum_char = pm_encoding_shift_jis_alnum_char, - .alpha_char = pm_encoding_shift_jis_alpha_char, - .isupper_char = pm_encoding_shift_jis_isupper_char, - .multibyte = true - }, [PM_ENCODING_WINDOWS_874] = { .name = "Windows-874", .char_width = pm_encoding_single_char_width, @@ -5002,6 +5015,7 @@ const pm_encoding_t pm_encodings[] = { .isupper_char = pm_encoding_windows_874_isupper_char, .multibyte = false } +#endif }; /** @@ -5016,11 +5030,13 @@ pm_encoding_find(const uint8_t *start, const uint8_t *end) { // UTF-8 can contain extra information at the end about the platform it is // encoded on, such as UTF-8-MAC or UTF-8-UNIX. We'll ignore those suffixes. if ((start + 5 <= end) && (pm_strncasecmp(start, (const uint8_t *) "UTF-8", 5) == 0)) { +#ifndef PRISM_ENCODING_EXCLUDE_FULL // We need to explicitly handle UTF-8-HFS, as that one needs to switch // over to being UTF8-MAC. if (width == 9 && (pm_strncasecmp(start + 5, (const uint8_t *) "-HFS", 4) == 0)) { return &pm_encodings[PM_ENCODING_UTF8_MAC]; } +#endif // Otherwise we'll return the default UTF-8 encoding. return PM_ENCODING_UTF_8_ENTRY; @@ -5040,11 +5056,16 @@ pm_encoding_find(const uint8_t *start, const uint8_t *end) { break; case 'B': case 'b': ENCODING1("BINARY", PM_ENCODING_ASCII_8BIT); +#ifndef PRISM_ENCODING_EXCLUDE_FULL ENCODING1("Big5", PM_ENCODING_BIG5); ENCODING2("Big5-HKSCS", "Big5-HKSCS:2008", PM_ENCODING_BIG5_HKSCS); ENCODING1("Big5-UAO", PM_ENCODING_BIG5_UAO); +#endif break; case 'C': case 'c': + ENCODING1("CP65001", PM_ENCODING_UTF_8); + ENCODING2("CP932", "csWindows31J", PM_ENCODING_WINDOWS_31J); +#ifndef PRISM_ENCODING_EXCLUDE_FULL ENCODING1("CESU-8", PM_ENCODING_CESU_8); ENCODING1("CP437", PM_ENCODING_IBM437); ENCODING1("CP720", PM_ENCODING_IBM720); @@ -5064,7 +5085,6 @@ pm_encoding_find(const uint8_t *start, const uint8_t *end) { ENCODING1("CP874", PM_ENCODING_WINDOWS_874); ENCODING1("CP878", PM_ENCODING_KOI8_R); ENCODING1("CP863", PM_ENCODING_IBM863); - ENCODING2("CP932", "csWindows31J", PM_ENCODING_WINDOWS_31J); ENCODING1("CP936", PM_ENCODING_GBK); ENCODING1("CP949", PM_ENCODING_CP949); ENCODING1("CP950", PM_ENCODING_CP950); @@ -5079,25 +5099,30 @@ pm_encoding_find(const uint8_t *start, const uint8_t *end) { ENCODING1("CP1257", PM_ENCODING_WINDOWS_1257); ENCODING1("CP1258", PM_ENCODING_WINDOWS_1258); ENCODING1("CP51932", PM_ENCODING_CP51932); - ENCODING1("CP65001", PM_ENCODING_UTF_8); +#endif break; case 'E': case 'e': ENCODING2("EUC-JP", "eucJP", PM_ENCODING_EUC_JP); +#ifndef PRISM_ENCODING_EXCLUDE_FULL ENCODING2("eucJP-ms", "euc-jp-ms", PM_ENCODING_EUC_JP_MS); ENCODING2("EUC-JIS-2004", "EUC-JISX0213", PM_ENCODING_EUC_JIS_2004); ENCODING2("EUC-KR", "eucKR", PM_ENCODING_EUC_KR); ENCODING2("EUC-CN", "eucCN", PM_ENCODING_GB2312); ENCODING2("EUC-TW", "eucTW", PM_ENCODING_EUC_TW); ENCODING1("Emacs-Mule", PM_ENCODING_EMACS_MULE); +#endif break; case 'G': case 'g': +#ifndef PRISM_ENCODING_EXCLUDE_FULL ENCODING1("GBK", PM_ENCODING_GBK); ENCODING1("GB12345", PM_ENCODING_GB12345); ENCODING1("GB18030", PM_ENCODING_GB18030); ENCODING1("GB1988", PM_ENCODING_GB1988); ENCODING1("GB2312", PM_ENCODING_GB2312); +#endif break; case 'I': case 'i': +#ifndef PRISM_ENCODING_EXCLUDE_FULL ENCODING1("IBM437", PM_ENCODING_IBM437); ENCODING1("IBM720", PM_ENCODING_IBM720); ENCODING1("IBM737", PM_ENCODING_IBM737); @@ -5129,12 +5154,16 @@ pm_encoding_find(const uint8_t *start, const uint8_t *end) { ENCODING2("ISO-8859-14", "ISO8859-14", PM_ENCODING_ISO_8859_14); ENCODING2("ISO-8859-15", "ISO8859-15", PM_ENCODING_ISO_8859_15); ENCODING2("ISO-8859-16", "ISO8859-16", PM_ENCODING_ISO_8859_16); +#endif break; case 'K': case 'k': +#ifndef PRISM_ENCODING_EXCLUDE_FULL ENCODING1("KOI8-R", PM_ENCODING_KOI8_R); ENCODING1("KOI8-U", PM_ENCODING_KOI8_U); +#endif break; case 'M': case 'm': +#ifndef PRISM_ENCODING_EXCLUDE_FULL ENCODING1("macCentEuro", PM_ENCODING_MAC_CENT_EURO); ENCODING1("macCroatian", PM_ENCODING_MAC_CROATIAN); ENCODING1("macCyrillic", PM_ENCODING_MAC_CYRILLIC); @@ -5147,31 +5176,39 @@ pm_encoding_find(const uint8_t *start, const uint8_t *end) { ENCODING1("macThai", PM_ENCODING_MAC_THAI); ENCODING1("macTurkish", PM_ENCODING_MAC_TURKISH); ENCODING1("macUkraine", PM_ENCODING_MAC_UKRAINE); +#endif break; case 'P': case 'p': ENCODING1("PCK", PM_ENCODING_WINDOWS_31J); break; case 'S': case 's': - ENCODING1("Shift_JIS", PM_ENCODING_SHIFT_JIS); ENCODING1("SJIS", PM_ENCODING_WINDOWS_31J); +#ifndef PRISM_ENCODING_EXCLUDE_FULL + ENCODING1("Shift_JIS", PM_ENCODING_SHIFT_JIS); ENCODING1("SJIS-DoCoMo", PM_ENCODING_SJIS_DOCOMO); ENCODING1("SJIS-KDDI", PM_ENCODING_SJIS_KDDI); ENCODING1("SJIS-SoftBank", PM_ENCODING_SJIS_SOFTBANK); ENCODING1("stateless-ISO-2022-JP", PM_ENCODING_STATELESS_ISO_2022_JP); ENCODING1("stateless-ISO-2022-JP-KDDI", PM_ENCODING_STATELESS_ISO_2022_JP_KDDI); +#endif break; case 'T': case 't': +#ifndef PRISM_ENCODING_EXCLUDE_FULL ENCODING1("TIS-620", PM_ENCODING_TIS_620); +#endif break; case 'U': case 'u': ENCODING1("US-ASCII", PM_ENCODING_US_ASCII); +#ifndef PRISM_ENCODING_EXCLUDE_FULL ENCODING2("UTF8-MAC", "UTF-8-HFS", PM_ENCODING_UTF8_MAC); ENCODING1("UTF8-DoCoMo", PM_ENCODING_UTF8_DOCOMO); ENCODING1("UTF8-KDDI", PM_ENCODING_UTF8_KDDI); ENCODING1("UTF8-SoftBank", PM_ENCODING_UTF8_SOFTBANK); +#endif break; case 'W': case 'w': ENCODING1("Windows-31J", PM_ENCODING_WINDOWS_31J); +#ifndef PRISM_ENCODING_EXCLUDE_FULL ENCODING1("Windows-874", PM_ENCODING_WINDOWS_874); ENCODING1("Windows-1250", PM_ENCODING_WINDOWS_1250); ENCODING1("Windows-1251", PM_ENCODING_WINDOWS_1251); @@ -5182,6 +5219,7 @@ pm_encoding_find(const uint8_t *start, const uint8_t *end) { ENCODING1("Windows-1256", PM_ENCODING_WINDOWS_1256); ENCODING1("Windows-1257", PM_ENCODING_WINDOWS_1257); ENCODING1("Windows-1258", PM_ENCODING_WINDOWS_1258); +#endif break; case '6': ENCODING1("646", PM_ENCODING_US_ASCII); diff --git a/prism/encoding.h b/prism/encoding.h index 0850e291d81f7e..5f7724821f5b31 100644 --- a/prism/encoding.h +++ b/prism/encoding.h @@ -135,7 +135,14 @@ extern const uint8_t pm_encoding_unicode_table[256]; */ typedef enum { PM_ENCODING_UTF_8 = 0, + PM_ENCODING_US_ASCII, PM_ENCODING_ASCII_8BIT, + PM_ENCODING_EUC_JP, + PM_ENCODING_WINDOWS_31J, + +// We optionally support excluding the full set of encodings to only support the +// minimum necessary to process Ruby code without encoding comments. +#ifndef PRISM_ENCODING_EXCLUDE_FULL PM_ENCODING_BIG5, PM_ENCODING_BIG5_HKSCS, PM_ENCODING_BIG5_UAO, @@ -148,7 +155,6 @@ typedef enum { PM_ENCODING_CP950, PM_ENCODING_CP951, PM_ENCODING_EMACS_MULE, - PM_ENCODING_EUC_JP, PM_ENCODING_EUC_JP_MS, PM_ENCODING_EUC_JIS_2004, PM_ENCODING_EUC_KR, @@ -208,7 +214,6 @@ typedef enum { PM_ENCODING_STATELESS_ISO_2022_JP, PM_ENCODING_STATELESS_ISO_2022_JP_KDDI, PM_ENCODING_TIS_620, - PM_ENCODING_US_ASCII, PM_ENCODING_UTF8_MAC, PM_ENCODING_UTF8_DOCOMO, PM_ENCODING_UTF8_KDDI, @@ -222,8 +227,9 @@ typedef enum { PM_ENCODING_WINDOWS_1256, PM_ENCODING_WINDOWS_1257, PM_ENCODING_WINDOWS_1258, - PM_ENCODING_WINDOWS_31J, PM_ENCODING_WINDOWS_874, +#endif + PM_ENCODING_MAXIMUM } pm_encoding_type_t; diff --git a/prism/extension.c b/prism/extension.c index 3672ee0dc58d36..7c8636e3dfc15c 100644 --- a/prism/extension.c +++ b/prism/extension.c @@ -311,7 +311,7 @@ dump(int argc, VALUE *argv, VALUE self) { pm_options_t options = { 0 }; string_options(argc, argv, &input, &options); -#ifdef PRISM_DEBUG_MODE_BUILD +#ifdef PRISM_BUILD_DEBUG size_t length = pm_string_length(&input); char* dup = xmalloc(length); memcpy(dup, pm_string_source(&input), length); @@ -320,7 +320,7 @@ dump(int argc, VALUE *argv, VALUE self) { VALUE value = dump_input(&input, &options); -#ifdef PRISM_DEBUG_MODE_BUILD +#ifdef PRISM_BUILD_DEBUG xfree(dup); #endif @@ -737,7 +737,7 @@ parse(int argc, VALUE *argv, VALUE self) { pm_options_t options = { 0 }; string_options(argc, argv, &input, &options); -#ifdef PRISM_DEBUG_MODE_BUILD +#ifdef PRISM_BUILD_DEBUG size_t length = pm_string_length(&input); char* dup = xmalloc(length); memcpy(dup, pm_string_source(&input), length); @@ -746,7 +746,7 @@ parse(int argc, VALUE *argv, VALUE self) { VALUE value = parse_input(&input, &options); -#ifdef PRISM_DEBUG_MODE_BUILD +#ifdef PRISM_BUILD_DEBUG xfree(dup); #endif diff --git a/prism/pack.c b/prism/pack.c index d5bfc4d6fdf97d..1388ca8a3b5210 100644 --- a/prism/pack.c +++ b/prism/pack.c @@ -1,16 +1,43 @@ #include "prism/pack.h" +// We optionally support parsing String#pack templates. For systems that don't +// want or need this functionality, it can be turned off with the +// PRISM_EXCLUDE_PACK define. +#ifdef PRISM_EXCLUDE_PACK + +void pm_pack_parse(void) {} + +#else + #include #include static uintmax_t -strtoumaxc(const char **format); +strtoumaxc(const char **format) { + uintmax_t value = 0; + while (**format >= '0' && **format <= '9') { + if (value > UINTMAX_MAX / 10) { + errno = ERANGE; + } + value = value * 10 + ((uintmax_t) (**format - '0')); + (*format)++; + } + return value; +} PRISM_EXPORTED_FUNCTION pm_pack_result -pm_pack_parse(pm_pack_variant variant, const char **format, const char *format_end, - pm_pack_type *type, pm_pack_signed *signed_type, pm_pack_endian *endian, pm_pack_size *size, - pm_pack_length_type *length_type, uint64_t *length, pm_pack_encoding *encoding) { - +pm_pack_parse( + pm_pack_variant variant, + const char **format, + const char *format_end, + pm_pack_type *type, + pm_pack_signed *signed_type, + pm_pack_endian *endian, + pm_pack_size *size, + pm_pack_length_type *length_type, + uint64_t *length, + pm_pack_encoding *encoding +) { if (*encoding == PM_PACK_ENCODING_START) { *encoding = PM_PACK_ENCODING_US_ASCII; } @@ -479,15 +506,4 @@ pm_size_to_native(pm_pack_size size) { } } -static uintmax_t -strtoumaxc(const char **format) { - uintmax_t value = 0; - while (**format >= '0' && **format <= '9') { - if (value > UINTMAX_MAX / 10) { - errno = ERANGE; - } - value = value * 10 + ((uintmax_t) (**format - '0')); - (*format)++; - } - return value; -} +#endif diff --git a/prism/pack.h b/prism/pack.h index e49484838970a8..cfdc251fe6d589 100644 --- a/prism/pack.h +++ b/prism/pack.h @@ -6,6 +6,15 @@ #ifndef PRISM_PACK_H #define PRISM_PACK_H +// We optionally support parsing String#pack templates. For systems that don't +// want or need this functionality, it can be turned off with the +// PRISM_EXCLUDE_PACK define. +#ifdef PRISM_EXCLUDE_PACK + +void pm_pack_parse(void); + +#else + #include "prism/defines.h" #include @@ -150,3 +159,5 @@ pm_pack_parse( PRISM_EXPORTED_FUNCTION size_t pm_size_to_native(pm_pack_size size); #endif + +#endif diff --git a/prism/prettyprint.h b/prism/prettyprint.h index 351b92df39510f..ea11b4a24687b3 100644 --- a/prism/prettyprint.h +++ b/prism/prettyprint.h @@ -6,6 +6,12 @@ #ifndef PRISM_PRETTYPRINT_H #define PRISM_PRETTYPRINT_H +#ifdef PRISM_EXCLUDE_PRETTYPRINT + +void pm_prettyprint(void); + +#else + #include "prism/defines.h" #include @@ -24,3 +30,5 @@ PRISM_EXPORTED_FUNCTION void pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node); #endif + +#endif diff --git a/prism/prism.c b/prism/prism.c index 955636027e392d..77cbcea2fe7a2d 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -973,9 +973,9 @@ pm_conditional_predicate(pm_parser_t *parser, pm_node_t *node, pm_conditional_pr /** * In a lot of places in the tree you can have tokens that are not provided but - * that do not cause an error. For example, in a method call without - * parentheses. In these cases we set the token to the "not provided" type. For - * example: + * that do not cause an error. For example, this happens in a method call + * without parentheses. In these cases we set the token to the "not provided" type. + * For example: * * pm_token_t token = not_provided(parser); */ @@ -1214,10 +1214,12 @@ pm_node_flag_set_repeated_parameter(pm_node_t *node) { * Parse out the options for a regular expression. */ static inline pm_node_flags_t -pm_regular_expression_flags_create(const pm_token_t *closing) { +pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) { pm_node_flags_t flags = 0; if (closing->type == PM_TOKEN_REGEXP_END) { + pm_buffer_t unknown_flags = { 0 }; + for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) { switch (*flag) { case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break; @@ -1230,9 +1232,16 @@ pm_regular_expression_flags_create(const pm_token_t *closing) { case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break; case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break; - default: assert(false && "unreachable"); + default: pm_buffer_append_byte(&unknown_flags, *flag); } } + + size_t unknown_flags_length = pm_buffer_length(&unknown_flags); + if (unknown_flags_length != 0) { + const char *word = unknown_flags_length >= 2 ? "options" : "option"; + PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags)); + } + pm_buffer_free(&unknown_flags); } return flags; @@ -4297,10 +4306,10 @@ pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expressio } static inline void -pm_interpolated_regular_expression_node_closing_set(pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) { +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(closing)); + pm_node_flag_set((pm_node_t *)node, pm_regular_expression_flags_create(parser, closing)); } /** @@ -5473,7 +5482,7 @@ pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *ope pm_range_node_t *node = PM_ALLOC_NODE(parser, pm_range_node_t); pm_node_flags_t flags = 0; - // Indicate that this node an exclusive range if the operator is `...`. + // Indicate that this node is an exclusive range if the operator is `...`. if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) { flags |= PM_RANGE_FLAGS_EXCLUDE_END; } @@ -5528,7 +5537,7 @@ pm_regular_expression_node_create_unescaped(pm_parser_t *parser, const pm_token_ *node = (pm_regular_expression_node_t) { { .type = PM_REGULAR_EXPRESSION_NODE, - .flags = pm_regular_expression_flags_create(closing) | PM_NODE_FLAG_STATIC_LITERAL, + .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL, .location = { .start = MIN(opening->start, closing->start), .end = MAX(opening->end, closing->end) @@ -7104,7 +7113,7 @@ peek(pm_parser_t *parser) { /** * If the character to be read matches the given value, then returns true and - * advanced the current pointer. + * advances the current pointer. */ static inline bool match(pm_parser_t *parser, uint8_t value) { @@ -8152,7 +8161,7 @@ lex_interpolation(pm_parser_t *parser, const uint8_t *pound) { return PM_TOKEN_STRING_CONTENT; } - // Now we'll check against the character the follows the #. If it constitutes + // Now we'll check against the character that follows the #. If it constitutes // valid interplation, we'll handle that, otherwise we'll return // PM_TOKEN_NOT_PROVIDED. switch (pound[1]) { @@ -8184,7 +8193,7 @@ lex_interpolation(pm_parser_t *parser, const uint8_t *pound) { return PM_TOKEN_EMBVAR; } - // If we didn't get an valid interpolation, then this is just regular + // If we didn't get a valid interpolation, then this is just regular // string content. This is like if we get "#@-". In this case the caller // should keep lexing. parser->current.end = pound + 1; @@ -9557,7 +9566,7 @@ parser_lex(pm_parser_t *parser) { // we need to return the call operator. if (next_content[0] == '.') { // To match ripper, we need to emit an ignored newline even though - // its a real newline in the case that we have a beginless range + // it's a real newline in the case that we have a beginless range // on a subsequent line. if (peek_at(parser, next_content + 1) == '.') { if (!lexed_comment) parser_lex_ignored_newline(parser); @@ -10503,7 +10512,7 @@ parser_lex(pm_parser_t *parser) { ) { // Since we know we're about to add an __END__ comment, we know we - // need at add all of the newlines to get the correct column + // need to add all of the newlines to get the correct column // information for it. const uint8_t *cursor = parser->current.end; while ((cursor = next_newline(cursor, parser->end - cursor)) != NULL) { @@ -11354,7 +11363,7 @@ parser_lex(pm_parser_t *parser) { case '\\': { // If we hit an escape, then we need to skip past // however many characters the escape takes up. However - // it's important that if \n or \r\n are escaped that we + // it's important that if \n or \r\n are escaped, we // stop looping before the newline and not after the // newline so that we can still potentially find the // terminator of the heredoc. @@ -11566,7 +11575,7 @@ pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = { [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH), [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH), - // &&= &= ^= = >>= <<= -= %= |= += /= *= **= + // &&= &= ^= = >>= <<= -= %= |= ||= += /= *= **= [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT, [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT, [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT, @@ -11835,7 +11844,6 @@ parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bo * CRuby parsers that are generated would resolve this by using a lookahead and * potentially backtracking. We attempt to do this by just looking at the next * token and making a decision based on that. I am not sure if this is going to - * * work in all cases, it may need to be refactored later. But it appears to work * for now. */ @@ -11868,7 +11876,7 @@ token_begins_expression_p(pm_token_type_t type) { case PM_TOKEN_SEMICOLON: // The reason we need this short-circuit is because we're using the // binding powers table to tell us if the subsequent token could - // potentially be the start of an expression . If there _is_ a binding + // potentially be the start of an expression. If there _is_ a binding // power for one of these tokens, then we should remove it from this list // and let it be handled by the default case below. assert(pm_binding_powers[type].left == PM_BINDING_POWER_UNSET); @@ -12433,7 +12441,7 @@ pm_when_clause_static_literals_add(pm_parser_t *parser, pm_static_literals_t *li } /** - * Parse all of the elements of a hash. returns true if a double splat was found. + * Parse all of the elements of a hash. Return true if a double splat was found. */ static bool parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node) { @@ -12871,7 +12879,7 @@ update_parameter_state(pm_parser_t *parser, pm_token_t *token, pm_parameters_ord if (state == PM_PARAMETERS_NO_CHANGE) return; // If we see another ordered argument after a optional argument - // we only continue parsing ordered arguments until we stop seeing ordered arguments + // 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; @@ -13322,7 +13330,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, bool def_p) { // The end node locations on rescue nodes will not be set correctly // since we won't know the end until we've found all consequent - // clauses. This sets the end location on all rescues once we know it + // clauses. This sets the end location on all rescues once we know it. if (current) { const uint8_t *end_to_set = current->base.location.end; current = parent_node->rescue_clause; @@ -15185,7 +15193,7 @@ parse_negative_numeric(pm_node_t *node) { } /** - * Returns a string content token at a particular location that is empty. + * Return a string content token at a particular location that is empty. */ static pm_token_t parse_strings_empty_content(const uint8_t *location) { @@ -17490,7 +17498,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM); } - pm_interpolated_regular_expression_node_closing_set(interpolated, &closing); + pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing); return (pm_node_t *) interpolated; } case PM_TOKEN_BACKTICK: @@ -17849,7 +17857,7 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding } /** - * Ensures a call node that is about to become a call operator node does not + * Ensure a call node that is about to become a call operator node does not * have arguments or a block attached. If it does, then we'll need to add an * error message and destroy the arguments/block. Ideally we would keep the node * around so that consumers would still have access to it, but we don't have a @@ -18790,8 +18798,8 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc case PM_RANGE_NODE: // Range operators are non-associative, so that it does not // associate with other range operators (i.e. `..1..` should be - // rejected.) For this reason, we check such a case for unary ranges - // here, and if so, it returns the node immediately, + // rejected). For this reason, we check such a case for unary ranges + // here, and if so, it returns the node immediately. if ((((pm_range_node_t *) node)->left == NULL) && pm_binding_powers[parser->current.type].left >= PM_BINDING_POWER_RANGE) { return node; } @@ -19316,6 +19324,41 @@ pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse return node; } +/** + * Parse the source and return true if it parses without errors or warnings. + */ +PRISM_EXPORTED_FUNCTION bool +pm_parse_success_p(const uint8_t *source, size_t size, const char *data) { + pm_options_t options = { 0 }; + pm_options_read(&options, data); + + pm_parser_t parser; + pm_parser_init(&parser, source, size, &options); + + pm_node_t *node = pm_parse(&parser); + pm_node_destroy(&parser, node); + + bool result = parser.error_list.size == 0 && parser.warning_list.size == 0; + pm_parser_free(&parser); + pm_options_free(&options); + + return result; +} + +#undef PM_CASE_KEYWORD +#undef PM_CASE_OPERATOR +#undef PM_CASE_WRITABLE +#undef PM_STRING_EMPTY +#undef PM_LOCATION_NODE_BASE_VALUE +#undef PM_LOCATION_NODE_VALUE +#undef PM_LOCATION_NULL_VALUE +#undef PM_LOCATION_TOKEN_VALUE + +// We optionally support serializing to a binary string. For systems that don't +// want or need this functionality, it can be turned off with the +// PRISM_EXCLUDE_SERIALIZATION define. +#ifndef PRISM_EXCLUDE_SERIALIZATION + static inline void pm_serialize_header(pm_buffer_t *buffer) { pm_buffer_append_string(buffer, "PRISM", 5); @@ -19402,14 +19445,7 @@ pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t s pm_options_free(&options); } -#undef PM_CASE_KEYWORD -#undef PM_CASE_OPERATOR -#undef PM_CASE_WRITABLE -#undef PM_STRING_EMPTY -#undef PM_LOCATION_NODE_BASE_VALUE -#undef PM_LOCATION_NODE_VALUE -#undef PM_LOCATION_NULL_VALUE -#undef PM_LOCATION_TOKEN_VALUE +#endif /** An error that is going to be formatted into the output. */ typedef struct { diff --git a/prism/prism.h b/prism/prism.h index 5e3919f40b8c94..34540b9441954a 100644 --- a/prism/prism.h +++ b/prism/prism.h @@ -98,6 +98,11 @@ typedef char * (pm_parse_stream_fgets_t)(char *string, int size, void *stream); */ PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *fgets, const pm_options_t *options); +// We optionally support serializing to a binary string. For systems that don't +// want or need this functionality, it can be turned off with the +// PRISM_EXCLUDE_SERIALIZATION define. +#ifndef PRISM_EXCLUDE_SERIALIZATION + /** * Parse and serialize the AST represented by the source that is read out of the * given stream into to the given buffer. @@ -185,6 +190,8 @@ PRISM_EXPORTED_FUNCTION void pm_serialize_lex(pm_buffer_t *buffer, const uint8_t */ PRISM_EXPORTED_FUNCTION void pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data); +#endif + /** * Parse the source and return true if it parses without errors or warnings. * @@ -220,6 +227,10 @@ const char * pm_token_type_human(pm_token_type_t token_type); */ PRISM_EXPORTED_FUNCTION void pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool colorize); +// We optionally support dumping to JSON. For systems that don't want or need +// this functionality, it can be turned off with the PRISM_EXCLUDE_JSON define. +#ifndef PRISM_EXCLUDE_JSON + /** * Dump JSON to the given buffer. * @@ -229,6 +240,8 @@ PRISM_EXPORTED_FUNCTION void pm_parser_errors_format(const pm_parser_t *parser, */ PRISM_EXPORTED_FUNCTION void pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node); +#endif + /** * @mainpage * diff --git a/prism/templates/src/diagnostic.c.erb b/prism/templates/src/diagnostic.c.erb index 2a3ac1993009e8..818b12d98be8c1 100644 --- a/prism/templates/src/diagnostic.c.erb +++ b/prism/templates/src/diagnostic.c.erb @@ -277,6 +277,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { [PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING] = { "incompatible character encoding: /%.*s/", PM_ERROR_LEVEL_FATAL }, [PM_ERR_REGEXP_NON_ESCAPED_MBC] = { "/.../n has a non escaped non ASCII character in non ASCII-8BIT script: /%.*s/", PM_ERROR_LEVEL_FATAL }, [PM_ERR_REGEXP_INVALID_UNICODE_RANGE] = { "invalid Unicode range: /%.*s/", PM_ERROR_LEVEL_FATAL }, + [PM_ERR_REGEXP_UNKNOWN_OPTIONS] = { "unknown regexp %s: %.*s", PM_ERROR_LEVEL_FATAL }, [PM_ERR_REGEXP_TERM] = { "expected a closing delimiter for the regular expression", PM_ERROR_LEVEL_FATAL }, [PM_ERR_REGEXP_UTF8_CHAR_NON_UTF8_REGEXP] = { "UTF-8 character in non UTF-8 regexp: /%s/", PM_ERROR_LEVEL_FATAL }, [PM_ERR_RESCUE_EXPRESSION] = { "expected a rescued expression", PM_ERROR_LEVEL_FATAL }, diff --git a/prism/templates/src/node.c.erb b/prism/templates/src/node.c.erb index 699fc00725a8d0..99a0c92fa94eef 100644 --- a/prism/templates/src/node.c.erb +++ b/prism/templates/src/node.c.erb @@ -247,6 +247,10 @@ pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *nod } } +// We optionally support dumping to JSON. For systems that don't want or need +// this functionality, it can be turned off with the PRISM_EXCLUDE_JSON define. +#ifndef PRISM_EXCLUDE_JSON + static void pm_dump_json_constant(pm_buffer_t *buffer, const pm_parser_t *parser, pm_constant_id_t constant_id) { const pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id); @@ -360,3 +364,5 @@ pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *no break; } } + +#endif diff --git a/prism/templates/src/prettyprint.c.erb b/prism/templates/src/prettyprint.c.erb index ef3385d1a66b95..27f44cd996f68a 100644 --- a/prism/templates/src/prettyprint.c.erb +++ b/prism/templates/src/prettyprint.c.erb @@ -1,6 +1,15 @@ <%# encoding: ASCII -%> #include "prism/prettyprint.h" +// We optionally support pretty printing nodes. For systems that don't want or +// need this functionality, it can be turned off with the +// PRISM_EXCLUDE_PRETTYPRINT define. +#ifdef PRISM_EXCLUDE_PRETTYPRINT + +void pm_prettyprint(void) {} + +#else + static inline void prettyprint_location(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_location_t *location) { pm_line_column_t start = pm_newline_list_line_column(&parser->newline_list, location->start, parser->start_line); @@ -154,3 +163,5 @@ pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_n prettyprint_node(output_buffer, parser, node, &prefix_buffer); pm_buffer_free(&prefix_buffer); } + +#endif diff --git a/prism/templates/src/serialize.c.erb b/prism/templates/src/serialize.c.erb index 27fde37f698601..94b976645dd1d1 100644 --- a/prism/templates/src/serialize.c.erb +++ b/prism/templates/src/serialize.c.erb @@ -1,5 +1,10 @@ #include "prism.h" +// We optionally support serializing to a binary string. For systems that don't +// want or need this functionality, it can be turned off with the +// PRISM_EXCLUDE_SERIALIZATION define. +#ifndef PRISM_EXCLUDE_SERIALIZATION + #include static inline uint32_t @@ -394,23 +399,4 @@ pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, pm_options_free(&options); } -/** - * Parse the source and return true if it parses without errors or warnings. - */ -PRISM_EXPORTED_FUNCTION bool -pm_parse_success_p(const uint8_t *source, size_t size, const char *data) { - pm_options_t options = { 0 }; - pm_options_read(&options, data); - - pm_parser_t parser; - pm_parser_init(&parser, source, size, &options); - - pm_node_t *node = pm_parse(&parser); - pm_node_destroy(&parser, node); - - bool result = parser.error_list.size == 0 && parser.warning_list.size == 0; - pm_parser_free(&parser); - pm_options_free(&options); - - return result; -} +#endif diff --git a/prism/util/pm_char.c b/prism/util/pm_char.c index 13eddbba481c9d..dce19abd1b102f 100644 --- a/prism/util/pm_char.c +++ b/prism/util/pm_char.c @@ -19,10 +19,10 @@ static const uint8_t pm_byte_table[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5x - 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 4, 4, // 6x - 0, 0, 0, 4, 0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, // 7x + 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 4x + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 5x + 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 6x + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 7x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax diff --git a/ruby_parser.c b/ruby_parser.c index d37dc388cd28df..6d85a72c5b0c18 100644 --- a/ruby_parser.c +++ b/ruby_parser.c @@ -685,6 +685,12 @@ static const rb_parser_config_t rb_global_parser_config = { .str_coderange_scan_restartable = str_coderange_scan_restartable, }; +const rb_parser_config_t * +rb_ruby_parser_config(void) +{ + return &rb_global_parser_config; +} + rb_parser_t * rb_parser_params_allocate(void) { diff --git a/spec/bundler/commands/exec_spec.rb b/spec/bundler/commands/exec_spec.rb index 9f5f12739aeaa0..d59b690d2f4ef4 100644 --- a/spec/bundler/commands/exec_spec.rb +++ b/spec/bundler/commands/exec_spec.rb @@ -885,7 +885,7 @@ def bin_path(a,b,c) let(:exit_code) { Bundler::GemNotFound.new.status_code } let(:expected) { "" } let(:expected_err) { <<-EOS.strip } -Could not find gem 'rack (= 2)' in locally installed gems. +Could not find gem 'rack (= 2)' in cached gems or installed locally. The source contains the following gems matching 'rack': * rack-0.9.1 @@ -915,7 +915,7 @@ def bin_path(a,b,c) let(:exit_code) { Bundler::GemNotFound.new.status_code } let(:expected) { "" } let(:expected_err) { <<-EOS.strip } -Could not find gem 'rack (= 2)' in locally installed gems. +Could not find gem 'rack (= 2)' in cached gems or installed locally. The source contains the following gems matching 'rack': * rack-1.0.0 diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index 45582fc7cee422..0f1aeef910650e 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -138,7 +138,7 @@ it "does not fetch remote specs when using the --local option" do bundle "lock --update --local", raise_on_error: false - expect(err).to match(/locally installed gems/) + expect(err).to match(/cached gems or installed locally/) end it "does not fetch remote checksums with --local" do @@ -1211,7 +1211,7 @@ Because rails >= 7.0.4 depends on railties = 7.0.4 and rails < 7.0.4 depends on railties = 7.0.3.1, railties = 7.0.3.1 OR = 7.0.4 is required. - So, because railties = 7.0.3.1 OR = 7.0.4 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally, + So, because railties = 7.0.3.1 OR = 7.0.4 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally, version solving has failed. ERR end @@ -1322,7 +1322,7 @@ Thus, rails >= 7.0.2.3, < 7.0.4 cannot be used. And because rails >= 7.0.4 depends on activemodel = 7.0.4, rails >= 7.0.2.3 requires activemodel = 7.0.4. - So, because activemodel = 7.0.4 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally + So, because activemodel = 7.0.4 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally and Gemfile depends on rails >= 7.0.2.3, version solving has failed. ERR diff --git a/spec/bundler/commands/post_bundle_message_spec.rb b/spec/bundler/commands/post_bundle_message_spec.rb index 3c7fd3486de8b9..07fd5a79e97d4d 100644 --- a/spec/bundler/commands/post_bundle_message_spec.rb +++ b/spec/bundler/commands/post_bundle_message_spec.rb @@ -120,7 +120,7 @@ gem "not-a-gem", :group => :development G expect(err).to include <<-EOS.strip -Could not find gem 'not-a-gem' in rubygems repository #{file_uri_for(gem_repo1)}/ or installed locally. +Could not find gem 'not-a-gem' in rubygems repository #{file_uri_for(gem_repo1)}/, cached gems or installed locally. EOS end diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index 2bde5a1586d7cd..2a09e0531ba7ea 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -1422,6 +1422,43 @@ end end + it "does not claim to update to Bundler version to a wrong version when cached gems are present" do + pristine_system_gems "bundler-2.99.0" + + build_repo4 do + build_gem "rack", "3.0.9.1" + + build_bundler "2.99.0" + end + + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + gem "rack" + G + + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + rack (3.0.9.1) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + rack + + BUNDLED WITH + 2.99.0 + L + + bundle :cache, verbose: true + + bundle :update, bundler: true, artifice: "compact_index", verbose: true, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + + expect(out).not_to include("Updating bundler to") + end + it "does not update the bundler version in the lockfile if the latest version is not compatible with current ruby", :ruby_repo do pristine_system_gems "bundler-2.3.9" diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb index 24cf30eadbe2ec..45ee7b44d111e3 100644 --- a/spec/bundler/install/gemfile/git_spec.rb +++ b/spec/bundler/install/gemfile/git_spec.rb @@ -929,7 +929,7 @@ gem "has_submodule" end G - expect(err).to match(%r{submodule >= 0 could not be found in rubygems repository #{file_uri_for(gem_repo1)}/ or installed locally}) + expect(err).to match(%r{submodule >= 0 could not be found in rubygems repository #{file_uri_for(gem_repo1)}/, cached gems or installed locally}) expect(the_bundle).not_to include_gems "has_submodule 1.0" end diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index daee8a27443158..a5ba76f4d9e26e 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -520,7 +520,7 @@ it "fails" do bundle :install, artifice: "compact_index", raise_on_error: false - expect(err).to include("Could not find gem 'private_gem_1' in rubygems repository https://gem.repo2/ or installed locally.") + expect(err).to include("Could not find gem 'private_gem_1' in rubygems repository https://gem.repo2/, cached gems or installed locally.") end end @@ -611,7 +611,7 @@ Could not find compatible versions Because every version of depends_on_rack depends on rack >= 0 - and rack >= 0 could not be found in rubygems repository https://gem.repo2/ or installed locally, + and rack >= 0 could not be found in rubygems repository https://gem.repo2/, cached gems or installed locally, depends_on_rack cannot be used. So, because Gemfile depends on depends_on_rack >= 0, version solving has failed. diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb index 3e13d00b546c8e..c81c7095b0e74a 100644 --- a/spec/bundler/install/gemfile/specific_platform_spec.rb +++ b/spec/bundler/install/gemfile/specific_platform_spec.rb @@ -395,7 +395,7 @@ G error_message = <<~ERROR.strip - Could not find gem 'sorbet-static (= 0.5.6433)' with platform 'arm64-darwin-21' in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally. + Could not find gem 'sorbet-static (= 0.5.6433)' with platform 'arm64-darwin-21' in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally. The source contains the following gems matching 'sorbet-static (= 0.5.6433)': * sorbet-static-0.5.6433-universal-darwin-20 @@ -434,7 +434,7 @@ Could not find compatible versions Because every version of sorbet depends on sorbet-static = 0.5.6433 - and sorbet-static = 0.5.6433 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally for any resolution platforms (arm64-darwin-21), + and sorbet-static = 0.5.6433 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally for any resolution platforms (arm64-darwin-21), sorbet cannot be used. So, because Gemfile depends on sorbet = 0.5.6433, version solving has failed. @@ -473,7 +473,7 @@ bundle "lock", raise_on_error: false, env: { "BUNDLE_FORCE_RUBY_PLATFORM" => "true" } expect(err).to include <<~ERROR.rstrip - Could not find gem 'sorbet-static (= 0.5.9889)' with platform 'ruby' in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally. + Could not find gem 'sorbet-static (= 0.5.9889)' with platform 'ruby' in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally. The source contains the following gems matching 'sorbet-static (= 0.5.9889)': * sorbet-static-0.5.9889-#{Gem::Platform.local} diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb index 5e0c88fc9510c3..8ef3984975458b 100644 --- a/spec/bundler/install/gems/flex_spec.rb +++ b/spec/bundler/install/gems/flex_spec.rb @@ -197,7 +197,7 @@ Could not find compatible versions Because rack-obama >= 2.0 depends on rack = 1.2 - and rack = 1.2 could not be found in rubygems repository #{file_uri_for(gem_repo2)}/ or installed locally, + and rack = 1.2 could not be found in rubygems repository #{file_uri_for(gem_repo2)}/, cached gems or installed locally, rack-obama >= 2.0 cannot be used. So, because Gemfile depends on rack-obama = 2.0, version solving has failed. diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb index b54674898da5b7..c5f9c4a3d3e456 100644 --- a/spec/bundler/install/gems/resolving_spec.rb +++ b/spec/bundler/install/gems/resolving_spec.rb @@ -434,7 +434,7 @@ end nice_error = <<~E.strip - Could not find gems matching 'sorbet-static (= 0.5.10554)' valid for all resolution platforms (arm64-darwin-21, aarch64-linux) in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally. + Could not find gems matching 'sorbet-static (= 0.5.10554)' valid for all resolution platforms (arm64-darwin-21, aarch64-linux) in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally. The source contains the following gems matching 'sorbet-static (= 0.5.10554)': * sorbet-static-0.5.10554-universal-darwin-21 @@ -490,7 +490,7 @@ it "raises a proper error" do nice_error = <<~E.strip - Could not find gems matching 'sorbet-static' valid for all resolution platforms (arm-linux, x86_64-linux) in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally. + Could not find gems matching 'sorbet-static' valid for all resolution platforms (arm-linux, x86_64-linux) in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally. The source contains the following gems matching 'sorbet-static': * sorbet-static-0.5.10696-x86_64-linux diff --git a/spec/bundler/install/yanked_spec.rb b/spec/bundler/install/yanked_spec.rb index 5aeabd2f236a71..7408c243272512 100644 --- a/spec/bundler/install/yanked_spec.rb +++ b/spec/bundler/install/yanked_spec.rb @@ -188,7 +188,7 @@ bundle :list, raise_on_error: false - expect(err).to include("Could not find rack-0.9.1 in locally installed gems") + expect(err).to include("Could not find rack-0.9.1 in cached gems or installed locally") expect(err).to_not include("Your bundle is locked to rack (0.9.1) from") expect(err).to_not include("If you haven't changed sources, that means the author of rack (0.9.1) has removed it.") expect(err).to_not include("You'll need to update your bundle to a different version of rack (0.9.1) that hasn't been removed in order to install.") @@ -197,7 +197,7 @@ lockfile lockfile.gsub(/PLATFORMS\n #{lockfile_platforms}/m, "PLATFORMS\n #{lockfile_platforms("ruby")}") bundle :list, raise_on_error: false - expect(err).to include("Could not find rack-0.9.1 in locally installed gems") + expect(err).to include("Could not find rack-0.9.1 in cached gems or installed locally") end it "does not suggest the author has yanked the gem when using more than one gem, but shows all gems that couldn't be found in the source" do @@ -224,7 +224,7 @@ bundle :list, raise_on_error: false - expect(err).to include("Could not find rack-0.9.1, rack_middleware-1.0 in locally installed gems") + expect(err).to include("Could not find rack-0.9.1, rack_middleware-1.0 in cached gems or installed locally") expect(err).to include("Install missing gems with `bundle install`.") expect(err).to_not include("Your bundle is locked to rack (0.9.1) from") expect(err).to_not include("If you haven't changed sources, that means the author of rack (0.9.1) has removed it.") diff --git a/spec/bundler/plugins/install_spec.rb b/spec/bundler/plugins/install_spec.rb index d4776bbed7d15a..86eb4e584c6a8b 100644 --- a/spec/bundler/plugins/install_spec.rb +++ b/spec/bundler/plugins/install_spec.rb @@ -92,16 +92,18 @@ expect(out).to include("Using foo 1.1") end - it "installs when --branch specified" do - bundle "plugin install foo --branch main --source #{file_uri_for(gem_repo2)}" + it "raises an error when when --branch specified" do + bundle "plugin install foo --branch main --source #{file_uri_for(gem_repo2)}", raise_on_error: false - expect(out).to include("Installed plugin foo") + expect(out).not_to include("Installed plugin foo") + + expect(err).to include("--branch can only be used with git sources") end - it "installs when --ref specified" do - bundle "plugin install foo --ref v1.2.3 --source #{file_uri_for(gem_repo2)}" + it "raises an error when --ref specified" do + bundle "plugin install foo --ref v1.2.3 --source #{file_uri_for(gem_repo2)}", raise_on_error: false - expect(out).to include("Installed plugin foo") + expect(err).to include("--ref can only be used with git sources") end it "raises error when both --branch and --ref options are specified" do diff --git a/spec/prism.mspec b/spec/prism.mspec new file mode 100644 index 00000000000000..99af52c0f1601c --- /dev/null +++ b/spec/prism.mspec @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +## Command line +MSpec.register(:exclude, "The -S command line option runs launcher found in PATH, but only code after the first /#!.*ruby.*/-ish line in target file") +MSpec.register(:exclude, /^The -x command line option/) +MSpec.register(:exclude, "The --enable and --disable flags can be used with frozen-string-literal") +MSpec.register(:exclude, /^The --enable-frozen-string-literal flag/) +MSpec.register(:exclude, "The --debug flag produces debugging info on attempted frozen string modification") + +## Language +MSpec.register(:exclude, "The BEGIN keyword runs multiple begins in FIFO order") +MSpec.register(:exclude, "Executing break from within a block works when passing through a super call") +MSpec.register(:exclude, "The defined? keyword when called with a method name in a void context warns about the void context when parsing it") +MSpec.register(:exclude, /^Hash literal expands an '\*\*\{\}'/) +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, "The next statement in a method is invalid and raises a SyntaxError") +MSpec.register(:exclude, "Pattern matching variable pattern does not support using variable name (except _) several times") +MSpec.register(:exclude, "Pattern matching Hash pattern raise SyntaxError when keys duplicate in pattern") +MSpec.register(:exclude, "Regexp with character classes supports [[:alpha:][:digit:][:etc:]] (predefined character classes)") +MSpec.register(:exclude, /^Regexps with encoding modifiers/) +MSpec.register(:exclude, "Regexps with grouping raises a SyntaxError when parentheses aren't balanced") +MSpec.register(:exclude, "Regexps with modifiers supports (?imx-imx) (inline modifiers)") +MSpec.register(:exclude, "Regexps with modifiers supports (?imx-imx:expr) (scoped inline modifiers)") +MSpec.register(:exclude, "Literal Regexps throws SyntaxError for malformed literals") +MSpec.register(:exclude, "The rescue keyword raises SyntaxError when else is used without rescue and ensure") +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, "Kernel#eval includes file and line information in syntax error") +MSpec.register(:exclude, "Kernel#eval evaluates string with given filename and negative linenumber") +MSpec.register(:exclude, "Kernel#eval with a magic encoding comment allows spaces before the magic encoding comment") +MSpec.register(:exclude, "Kernel#eval with a magic encoding comment allows a shebang line and some spaces before the magic encoding comment") +MSpec.register(:exclude, "Kernel#eval with a magic encoding comment ignores the frozen_string_literal magic comment if it appears after a token and warns if $VERBOSE is true") +MSpec.register(:exclude, "Regexp#source has US-ASCII encoding when created from an ASCII-only \\u{} literal") +MSpec.register(:exclude, "TracePoint#eval_script is the evald source code") +MSpec.register(:exclude, "TracePoint#event returns the type of event") +MSpec.register(:exclude, "TracePoint#inspect returns a String showing the event, method, path and line for a :return event") +MSpec.register(:exclude, "TracePoint#inspect returns a String showing the event, path and line for a :class 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") +MSpec.register(:exclude, "TracePoint#self return the class object from a class event") +MSpec.register(:exclude, "Warning.[] returns default values for categories :deprecated and :experimental") + +## 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") +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, "Digest::SHA256.file when passed a path to a file that exists can be used with frozen-string-literal") +MSpec.register(:exclude, "ERB#filename raises an exception if there are errors processing content") +MSpec.register(:exclude, "ERB#filename uses '(erb)' as filename when filename is not set") +MSpec.register(:exclude, "mkmf can be required with --enable-frozen-string-literal") +MSpec.register(:exclude, "RbConfig::CONFIG contains no frozen strings even with --enable-frozen-string-literal") +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/command_line/dash_v_spec.rb b/spec/ruby/command_line/dash_v_spec.rb index 15569fa6423b9b..747db7f755888b 100644 --- a/spec/ruby/command_line/dash_v_spec.rb +++ b/spec/ruby/command_line/dash_v_spec.rb @@ -6,7 +6,7 @@ describe "when used alone" do it "prints version and ends" do - ruby_exe(nil, args: '-v').sub("+PRISM ", "").should include(RUBY_DESCRIPTION) + ruby_exe(nil, args: '-v').sub("+PRISM ", "").should include(RUBY_DESCRIPTION.sub("+PRISM ", "")) end unless (defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?) || (defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled?) || (ENV['RUBY_MN_THREADS'] == '1') diff --git a/spec/ruby/command_line/rubyopt_spec.rb b/spec/ruby/command_line/rubyopt_spec.rb index 734db8d519e29b..18a5959b18cd46 100644 --- a/spec/ruby/command_line/rubyopt_spec.rb +++ b/spec/ruby/command_line/rubyopt_spec.rb @@ -25,12 +25,12 @@ guard -> { not CROSS_COMPILING } do it "prints the version number for '-v'" do ENV["RUBYOPT"] = '-v' - ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION + ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION.sub("+PRISM ", "") end it "ignores whitespace around the option" do ENV["RUBYOPT"] = ' -v ' - ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION + ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION.sub("+PRISM ", "") end end diff --git a/spec/ruby/core/exception/top_level_spec.rb b/spec/ruby/core/exception/top_level_spec.rb index 6ef75395984454..cc961d06d565df 100644 --- a/spec/ruby/core/exception/top_level_spec.rb +++ b/spec/ruby/core/exception/top_level_spec.rb @@ -8,25 +8,32 @@ it "the Exception#cause is printed to STDERR with backtraces" do code = <<-RUBY def raise_cause - raise "the cause" + raise "the cause" # 2 end def raise_wrapped - raise "wrapped" + raise "wrapped" # 5 end begin - raise_cause + raise_cause # 8 rescue - raise_wrapped + raise_wrapped # 10 end RUBY lines = ruby_exe(code, args: "2>&1", exit_status: 1).lines - lines.map! { |l| l.chomp[/:(in.+)/, 1] } - lines.size.should == 5 - lines[0].should =~ /\Ain [`'](?:Object#)?raise_wrapped': wrapped \(RuntimeError\)\z/ - lines[1].should =~ /\Ain [`'](?:rescue in )?
'\z/ - lines[2].should =~ /\Ain [`']
'\z/ - lines[3].should =~ /\Ain [`'](?:Object#)?raise_cause': the cause \(RuntimeError\)\z/ - lines[4].should =~ /\Ain [`']
'\z/ + + lines.map! { |l| l.chomp[/:(\d+:in.+)/, 1] } + lines[0].should =~ /\A5:in [`'](?:Object#)?raise_wrapped': wrapped \(RuntimeError\)\z/ + if lines[1].include? 'rescue in' + # CRuby < 3.4 has an extra 'rescue in' backtrace entry + lines[1].should =~ /\A10:in [`']rescue in
'\z/ + lines.delete_at 1 + lines[1].should =~ /\A7:in [`']
'\z/ + else + lines[1].should =~ /\A10:in [`']
'\z/ + end + lines[2].should =~ /\A2:in [`'](?:Object#)?raise_cause': the cause \(RuntimeError\)\z/ + lines[3].should =~ /\A8:in [`']
'\z/ + lines.size.should == 4 end describe "with a custom backtrace" do diff --git a/spec/ruby/language/ensure_spec.rb b/spec/ruby/language/ensure_spec.rb index e893904bcb16d5..175222c86e01dc 100644 --- a/spec/ruby/language/ensure_spec.rb +++ b/spec/ruby/language/ensure_spec.rb @@ -328,4 +328,21 @@ class EnsureInClassExample result.should == :begin end + + ruby_version_is "3.4" do + it "does not introduce extra backtrace entries" do + def foo + begin + raise "oops" + ensure + return caller(0, 2) + end + end + line = __LINE__ + foo.should == [ + "#{__FILE__}:#{line-3}:in 'foo'", + "#{__FILE__}:#{line+1}:in 'block (3 levels) in '" + ] + end + end end diff --git a/spec/ruby/language/rescue_spec.rb b/spec/ruby/language/rescue_spec.rb index d6e7b6c802464c..a3ee4807acd0ae 100644 --- a/spec/ruby/language/rescue_spec.rb +++ b/spec/ruby/language/rescue_spec.rb @@ -553,6 +553,23 @@ class RescueInClassExample eval('1.+((1 rescue 1))').should == 2 end + ruby_version_is "3.4" do + it "does not introduce extra backtrace entries" do + def foo + begin + raise "oops" + rescue + return caller(0, 2) + end + end + line = __LINE__ + foo.should == [ + "#{__FILE__}:#{line-3}:in 'foo'", + "#{__FILE__}:#{line+1}:in 'block (3 levels) in '" + ] + end + end + describe "inline form" do it "can be inlined" do a = 1/0 rescue 1 diff --git a/string.c b/string.c index 07a757386f26bc..87ed6fefdf8f36 100644 --- a/string.c +++ b/string.c @@ -1350,7 +1350,7 @@ rb_str_new_shared(VALUE str) VALUE rb_str_new_frozen(VALUE orig) { - if (OBJ_FROZEN(orig)) return orig; + if (RB_FL_TEST_RAW(orig, FL_FREEZE | STR_CHILLED) == FL_FREEZE) return orig; return str_new_frozen(rb_obj_class(orig), orig); } diff --git a/template/Doxyfile.tmpl b/template/Doxyfile.tmpl index c04f14977de323..cea28d04c7d278 100644 --- a/template/Doxyfile.tmpl +++ b/template/Doxyfile.tmpl @@ -2359,10 +2359,6 @@ PREDEFINED += DEPRECATED(_)=_ PREDEFINED += DEPRECATED_BY(__,_)=_ PREDEFINED += ENUM_OVER_INT=1 PREDEFINED += ERRORFUNC(__,_)=_ -PREDEFINED += RJIT_FUNC_EXPORTED= -PREDEFINED += RJIT_STATIC=extern -PREDEFINED += RJIT_SYMBOL_EXPORT_BEGIN= -PREDEFINED += RJIT_SYMBOL_EXPORT_END= PREDEFINED += NOINLINE(_)=_ PREDEFINED += NORETURN(_)=_ PREDEFINED += PACKED_STRUCT_UNALIGNED(_)=_ diff --git a/test/irb/test_input_method.rb b/test/irb/test_input_method.rb index 7644d3176aabb7..ce317b4b32ed3d 100644 --- a/test/irb/test_input_method.rb +++ b/test/irb/test_input_method.rb @@ -88,17 +88,18 @@ def setup @driver = RDoc::RI::Driver.new(use_stdout: true) end - def display_document(target, bind) + def display_document(target, bind, driver = nil) input_method = IRB::RelineInputMethod.new(IRB::RegexpCompletor.new) + input_method.instance_variable_set(:@rdoc_ri_driver, driver) if driver input_method.instance_variable_set(:@completion_params, ['', target, '', bind]) - input_method.display_document(target, driver: @driver) + input_method.display_document(target) end def test_perfectly_matched_namespace_triggers_document_display omit unless has_rdoc_content? out, err = capture_output do - display_document("String", binding) + display_document("String", binding, @driver) end assert_empty(err) @@ -109,7 +110,7 @@ def test_perfectly_matched_namespace_triggers_document_display def test_perfectly_matched_multiple_namespaces_triggers_document_display result = nil out, err = capture_output do - result = display_document("{}.nil?", binding) + result = display_document("{}.nil?", binding, @driver) end assert_empty(err) @@ -131,7 +132,7 @@ def test_perfectly_matched_multiple_namespaces_triggers_document_display def test_not_matched_namespace_triggers_nothing result = nil out, err = capture_output do - result = display_document("Stri", binding) + result = display_document("Stri", binding, @driver) end assert_empty(err) @@ -156,7 +157,7 @@ def test_perfect_matching_stops_without_rdoc def test_perfect_matching_handles_nil_namespace out, err = capture_output do # symbol literal has `nil` doc namespace so it's a good test subject - assert_nil(display_document(":aiueo", binding)) + assert_nil(display_document(":aiueo", binding, @driver)) end assert_empty(err) diff --git a/test/irb/test_irb.rb b/test/irb/test_irb.rb index 8c4fb5ddee3d7a..966c840135c74f 100644 --- a/test/irb/test_irb.rb +++ b/test/irb/test_irb.rb @@ -70,11 +70,8 @@ def test_empty_input_echoing_behaviour type "exit" end - # Input cramped together due to how Reline's Reline::GeneralIO works - assert_include( - output, - "irb(main):001> irb(main):002> irb(main):002> irb(main):002> => nil\r\n" - ) + assert_not_match(/irb\(main\):001> (\r*\n)?=> nil/, output) + assert_match(/irb\(main\):002> (\r*\n)?=> nil/, output) end end diff --git a/test/irb/yamatanooroti/test_rendering.rb b/test/irb/yamatanooroti/test_rendering.rb index 511df58ea6c930..44e07a3a1232c1 100644 --- a/test/irb/yamatanooroti/test_rendering.rb +++ b/test/irb/yamatanooroti/test_rendering.rb @@ -137,6 +137,7 @@ def b; true; end a .a .b + .itself EOC close assert_screen(<<~EOC) @@ -153,9 +154,10 @@ def b; true; end irb(main):008> irb(main):009> a irb(main):010> .a - irb(main):011> .b + irb(main):011> .b + irb(main):012> .itself => true - irb(main):012> + irb(main):013> EOC end @@ -181,7 +183,6 @@ def c; true; end (a) &.b() - class A def b; self; end; def c; true; end; end; a = A.new a @@ -190,6 +191,7 @@ class A def b; self; end; def c; true; end; end; .c (a) &.b() + .itself EOC close assert_screen(<<~EOC) @@ -214,17 +216,17 @@ class A def b; self; end; def c; true; end; end; irb(main):015> &.b() => # irb(main):016> - irb(main):017> - irb(main):018> class A def b; self; end; def c; true; end; end; - irb(main):019> a = A.new + irb(main):017> class A def b; self; end; def c; true; end; end; + irb(main):018> a = A.new => # - irb(main):020> a - irb(main):021> .b - irb(main):022> # aaa - irb(main):023> .c + irb(main):019> a + irb(main):020> .b + irb(main):021> # aaa + irb(main):022> .c => true - irb(main):024> (a) - irb(main):025> &.b() + irb(main):023> (a) + irb(main):024> &.b() + irb(main):025> .itself => # irb(main):026> EOC @@ -254,9 +256,9 @@ def test_autocomplete_with_multiple_doc_namespaces start_terminal(3, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') write("{}.__id_") write("\C-i") + sleep 0.2 close screen = result.join("\n").sub(/\n*\z/, "\n") - # This assertion passes whether showdoc dialog completed or not. assert_match(/start\ IRB\nirb\(main\):001> {}\.__id__\n }\.__id__(?:Press )?/, screen) end @@ -276,6 +278,7 @@ def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_right start_terminal(4, 19, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') write("IR") write("\C-i") + sleep 0.2 close # This is because on macOS we display different shortcut for displaying the full doc @@ -313,6 +316,7 @@ def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_left start_terminal(4, 12, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') write("IR") write("\C-i") + sleep 0.2 close assert_screen(<<~EOC) start IRB diff --git a/test/prism/encoding_test.rb b/test/prism/encoding_test.rb index c23bb8c294b722..649d05b874164b 100644 --- a/test/prism/encoding_test.rb +++ b/test/prism/encoding_test.rb @@ -9,10 +9,13 @@ class EncodingTest < TestCase codepoints_1byte = 0...0x100 encodings = { Encoding::ASCII_8BIT => codepoints_1byte, - Encoding::US_ASCII => codepoints_1byte, - Encoding::Windows_1253 => codepoints_1byte + Encoding::US_ASCII => codepoints_1byte } + if !ENV["PRISM_BUILD_MINIMAL"] + encodings[Encoding::Windows_1253] = codepoints_1byte + end + # By default we don't test every codepoint in these encodings because it # takes a very long time. if ENV["PRISM_TEST_ALL_ENCODINGS"] @@ -205,21 +208,6 @@ def test_emacs_style assert_equal Encoding.find("utf-8"), actual end - # This test may be a little confusing. Basically when we use our strpbrk, it - # takes into account the encoding of the file. - def test_strpbrk_multibyte - result = Prism.parse(<<~RUBY) - # encoding: Shift_JIS - %w[\x81\x5c] - RUBY - - assert(result.errors.empty?) - assert_equal( - (+"\x81\x5c").force_encoding(Encoding::Shift_JIS), - result.value.statements.body.first.elements.first.unescaped - ) - end - def test_utf_8_variations %w[ utf-8-unix @@ -238,22 +226,39 @@ def test_first_lexed_token assert_equal Encoding.find("ascii-8bit"), encoding end - def test_slice_encoding - slice = Prism.parse("# encoding: Shift_JIS\nア").value.slice - assert_equal (+"ア").force_encoding(Encoding::SHIFT_JIS), slice - assert_equal Encoding::SHIFT_JIS, slice.encoding - end + if !ENV["PRISM_BUILD_MINIMAL"] + # This test may be a little confusing. Basically when we use our strpbrk, + # it takes into account the encoding of the file. + def test_strpbrk_multibyte + result = Prism.parse(<<~RUBY) + # encoding: Shift_JIS + %w[\x81\x5c] + RUBY + + assert(result.errors.empty?) + assert_equal( + (+"\x81\x5c").force_encoding(Encoding::Shift_JIS), + result.value.statements.body.first.elements.first.unescaped + ) + end - def test_multibyte_escapes - [ - ["'", "'"], - ["\"", "\""], - ["`", "`"], - ["/", "/"], - ["<<'HERE'\n", "\nHERE"], - ["<<-HERE\n", "\nHERE"] - ].each do |opening, closing| - assert Prism.parse_success?("# encoding: shift_jis\n'\\\x82\xA0'\n") + def test_slice_encoding + slice = Prism.parse("# encoding: Shift_JIS\nア").value.slice + assert_equal (+"ア").force_encoding(Encoding::SHIFT_JIS), slice + assert_equal Encoding::SHIFT_JIS, slice.encoding + end + + def test_multibyte_escapes + [ + ["'", "'"], + ["\"", "\""], + ["`", "`"], + ["/", "/"], + ["<<'HERE'\n", "\nHERE"], + ["<<-HERE\n", "\nHERE"] + ].each do |opening, closing| + assert Prism.parse_success?("# encoding: shift_jis\n'\\\x82\xA0'\n") + end end end diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb index ccf7485c7bdb26..9221d52ef35a4c 100644 --- a/test/prism/errors_test.rb +++ b/test/prism/errors_test.rb @@ -2067,6 +2067,20 @@ def test_it_with_ordinary_parameter assert_errors expression(source), source, errors, compare_ripper: false end + def test_regular_expression_with_unknown_regexp_options + source = "/foo/AZaz" + errors = [["unknown regexp options: AZaz", 4..9]] + + assert_errors expression(source), source, errors + end + + def test_interpolated_regular_expression_with_unknown_regexp_options + source = "/\#{foo}/AZaz" + errors = [["unknown regexp options: AZaz", 7..12]] + + assert_errors expression(source), source, errors + end + def test_singleton_method_for_literals source = <<~'RUBY' def (1).g; end diff --git a/test/prism/fuzzer_test.rb b/test/prism/fuzzer_test.rb index ac112f897ac762..511210e7ee1fec 100644 --- a/test/prism/fuzzer_test.rb +++ b/test/prism/fuzzer_test.rb @@ -1,9 +1,12 @@ # frozen_string_literal: true +return if ENV["PRISM_BUILD_MINIMAL"] + require_relative "test_helper" module Prism - # These tests are simply to exercise snippets found by the fuzzer that caused invalid memory access. + # These tests are simply to exercise snippets found by the fuzzer that caused + # invalid memory access. class FuzzerTest < TestCase def self.snippet(name, source) define_method(:"test_fuzzer_#{name}") { Prism.dump(source) } diff --git a/test/prism/location_test.rb b/test/prism/location_test.rb index c7ce248b569f00..b7b9a754cae781 100644 --- a/test/prism/location_test.rb +++ b/test/prism/location_test.rb @@ -527,6 +527,7 @@ def test_InterpolatedMatchLastLineNode def test_InterpolatedRegularExpressionNode assert_location(InterpolatedRegularExpressionNode, "/\#{foo}/") + assert_location(InterpolatedRegularExpressionNode, "/\#{foo}/io") end def test_InterpolatedStringNode @@ -730,6 +731,7 @@ def test_RedoNode def test_RegularExpressionNode assert_location(RegularExpressionNode, "/foo/") + assert_location(RegularExpressionNode, "/foo/io") end def test_RequiredKeywordParameterNode diff --git a/test/prism/magic_comment_test.rb b/test/prism/magic_comment_test.rb index 5e232c2d004cd1..4c02af732cf993 100644 --- a/test/prism/magic_comment_test.rb +++ b/test/prism/magic_comment_test.rb @@ -17,11 +17,11 @@ class MagicCommentTest < TestCase "# -*- \s\t\v encoding \s\t\v : \s\t\v ascii \s\t\v -*-", "# -*- foo: bar; encoding: ascii -*-", "# coding \t \r \v : \t \v \r ascii-8bit", - "# vim: filetype=ruby, fileencoding=big5, tabsize=3, shiftwidth=3" + "# vim: filetype=ruby, fileencoding=windows-31j, tabsize=3, shiftwidth=3" ] - examples.each do |example| - define_method(:"test_magic_comment_#{example}") do + examples.each.with_index(1) do |example, index| + define_method(:"test_magic_comment_#{index}") do assert_magic_comment(example) end end diff --git a/test/prism/parse_test.rb b/test/prism/parse_test.rb index 574a1c1714f8d1..db66b431ba7ad0 100644 --- a/test/prism/parse_test.rb +++ b/test/prism/parse_test.rb @@ -75,19 +75,21 @@ def test_parse_lex assert_equal 5, tokens.length end - def test_dump_file - assert_nothing_raised do - Prism.dump_file(__FILE__) - end + if !ENV["PRISM_BUILD_MINIMAL"] + def test_dump_file + assert_nothing_raised do + Prism.dump_file(__FILE__) + end - error = assert_raise Errno::ENOENT do - Prism.dump_file("idontexist.rb") - end + error = assert_raise Errno::ENOENT do + Prism.dump_file("idontexist.rb") + end - assert_equal "No such file or directory - idontexist.rb", error.message + assert_equal "No such file or directory - idontexist.rb", error.message - assert_raise TypeError do - Prism.dump_file(nil) + assert_raise TypeError do + Prism.dump_file(nil) + end end end @@ -259,9 +261,11 @@ def test_parse_file_comments warn("Created snapshot at #{snapshot}.") end - # Next, assert that the value can be serialized and deserialized without - # changing the shape of the tree. - assert_equal_nodes(result.value, Prism.load(source, Prism.dump(source, filepath: relative)).value) + if !ENV["PRISM_BUILD_MINIMAL"] + # Next, assert that the value can be serialized and deserialized + # without changing the shape of the tree. + assert_equal_nodes(result.value, Prism.load(source, Prism.dump(source, filepath: relative)).value) + end # Next, check that the location ranges of each node in the tree are a # superset of their respective child nodes. @@ -318,7 +322,9 @@ def test_parse_file_comments result = Prism.parse(snippet, filepath: relative) assert_empty result.errors - assert_equal_nodes(result.value, Prism.load(snippet, Prism.dump(snippet, filepath: relative)).value) + if !ENV["PRISM_BUILD_MINIMAL"] + assert_equal_nodes(result.value, Prism.load(snippet, Prism.dump(snippet, filepath: relative)).value) + end end end end diff --git a/test/prism/ruby_api_test.rb b/test/prism/ruby_api_test.rb index 80f7cb05d3e66f..4153a69ad75644 100644 --- a/test/prism/ruby_api_test.rb +++ b/test/prism/ruby_api_test.rb @@ -4,20 +4,22 @@ module Prism class RubyAPITest < TestCase - def test_ruby_api - filepath = __FILE__ - source = File.read(filepath, binmode: true, external_encoding: Encoding::UTF_8) + if !ENV["PRISM_BUILD_MINIMAL"] + def test_ruby_api + filepath = __FILE__ + source = File.read(filepath, binmode: true, external_encoding: Encoding::UTF_8) - assert_equal Prism.lex(source, filepath: filepath).value, Prism.lex_file(filepath).value - assert_equal Prism.dump(source, filepath: filepath), Prism.dump_file(filepath) + assert_equal Prism.lex(source, filepath: filepath).value, Prism.lex_file(filepath).value + assert_equal Prism.dump(source, filepath: filepath), Prism.dump_file(filepath) - serialized = Prism.dump(source, filepath: filepath) - ast1 = Prism.load(source, serialized).value - ast2 = Prism.parse(source, filepath: filepath).value - ast3 = Prism.parse_file(filepath).value + serialized = Prism.dump(source, filepath: filepath) + ast1 = Prism.load(source, serialized).value + ast2 = Prism.parse(source, filepath: filepath).value + ast3 = Prism.parse_file(filepath).value - assert_equal_nodes ast1, ast2 - assert_equal_nodes ast2, ast3 + assert_equal_nodes ast1, ast2 + assert_equal_nodes ast2, ast3 + end end def test_parse_success? diff --git a/test/prism/ruby_parser_test.rb b/test/prism/ruby_parser_test.rb index 1d22f0e7b8729f..952e493af9159c 100644 --- a/test/prism/ruby_parser_test.rb +++ b/test/prism/ruby_parser_test.rb @@ -18,7 +18,7 @@ Sexp.prepend( Module.new do def ==(other) - super && line == other.line && max_line == other.max_line && file == other.file + super && line == other.line && line_max == other.line_max && file == other.file end end ) diff --git a/test/prism/static_inspect_test.rb b/test/prism/static_inspect_test.rb index 41301693e3b76d..8df2fd241e0eb3 100644 --- a/test/prism/static_inspect_test.rb +++ b/test/prism/static_inspect_test.rb @@ -54,7 +54,7 @@ def test_regular_expression def test_source_encoding assert_equal "#", static_inspect("__ENCODING__") - assert_equal "#", static_inspect("__ENCODING__", encoding: "Shift_JIS") + assert_equal "#", static_inspect("__ENCODING__", encoding: "Windows-31J") end def test_source_file diff --git a/test/reline/helper.rb b/test/reline/helper.rb index 2180fdf5969abe..f2f3421ded0bf4 100644 --- a/test/reline/helper.rb +++ b/test/reline/helper.rb @@ -78,14 +78,6 @@ def test_rubybin end end -def start_pasting - Reline::GeneralIO.start_pasting -end - -def finish_pasting - Reline::GeneralIO.finish_pasting -end - class Reline::TestCase < Test::Unit::TestCase private def convert_str(input, options = {}, normalized = nil) return nil if input.nil? @@ -136,9 +128,14 @@ def input_raw_keys(input, convert = true) end end - def assert_line(expected) - expected = convert_str(expected) - assert_equal(expected, @line_editor.line) + def assert_line_around_cursor(before, after) + before = convert_str(before) + after = convert_str(after) + line = @line_editor.line + byte_pointer = @line_editor.instance_variable_get(:@byte_pointer) + actual_before = line.byteslice(0, byte_pointer) + actual_after = line.byteslice(byte_pointer..) + assert_equal([before, after], [actual_before, actual_after]) end def assert_byte_pointer_size(expected) @@ -153,25 +150,6 @@ def assert_byte_pointer_size(expected) EOM end - def assert_cursor(expected) - # This test satisfies nothing because there is no `@cursor` anymore - # Test editor_cursor_position instead - cursor_x = @line_editor.instance_eval do - line_before_cursor = whole_lines[@line_index].byteslice(0, @byte_pointer) - Reline::Unicode.calculate_width(line_before_cursor) - end - assert_equal(expected, cursor_x) - end - - def assert_cursor_max(expected) - # This test satisfies nothing because there is no `@cursor_max` anymore - cursor_max = @line_editor.instance_eval do - line = whole_lines[@line_index] - Reline::Unicode.calculate_width(line) - end - assert_equal(expected, cursor_max) - end - def assert_line_index(expected) assert_equal(expected, @line_editor.instance_variable_get(:@line_index)) end diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb index d5ddd40f8526cf..2311af0f5aad26 100644 --- a/test/reline/test_key_actor_emacs.rb +++ b/test/reline/test_key_actor_emacs.rb @@ -19,418 +19,238 @@ def teardown def test_ed_insert_one input_keys('a') - assert_line('a') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(1) + assert_line_around_cursor('a', '') end def test_ed_insert_two input_keys('ab') - assert_line('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') end def test_ed_insert_mbchar_one input_keys('か') - assert_line('か') - assert_byte_pointer_size('か') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('か', '') end def test_ed_insert_mbchar_two input_keys('かき') - assert_line('かき') - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('かき', '') end def test_ed_insert_for_mbchar_by_plural_code_points input_keys("か\u3099") - assert_line("か\u3099") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor("か\u3099", '') end def test_ed_insert_for_plural_mbchar_by_plural_code_points input_keys("か\u3099き\u3099") - assert_line("か\u3099き\u3099") - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor("か\u3099き\u3099", '') end def test_move_next_and_prev input_keys('abd') - assert_byte_pointer_size('abd') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abd', '') input_keys("\C-b", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'd') input_keys("\C-b", false) - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) + assert_line_around_cursor('a', 'bd') input_keys("\C-f", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'd') input_keys('c') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(4) - assert_line('abcd') + assert_line_around_cursor('abc', 'd') end def test_move_next_and_prev_for_mbchar input_keys('かきけ') - assert_byte_pointer_size('かきけ') - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor('かきけ', '') input_keys("\C-b", false) - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor('かき', 'け') input_keys("\C-b", false) - assert_byte_pointer_size('か') - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor('か', 'きけ') input_keys("\C-f", false) - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor('かき', 'け') input_keys('く') - assert_byte_pointer_size('かきく') - assert_cursor(6) - assert_cursor_max(8) - assert_line('かきくけ') + assert_line_around_cursor('かきく', 'け') end def test_move_next_and_prev_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099け\u3099") - assert_byte_pointer_size("か\u3099き\u3099け\u3099") - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099け\u3099", '') input_keys("\C-b", false) - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099", "け\u3099") input_keys("\C-b", false) - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099", "き\u3099け\u3099") input_keys("\C-f", false) - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099", "け\u3099") input_keys("く\u3099") - assert_byte_pointer_size("か\u3099き\u3099く\u3099") - assert_cursor(6) - assert_cursor_max(8) - assert_line("か\u3099き\u3099く\u3099け\u3099") + assert_line_around_cursor("か\u3099き\u3099く\u3099", "け\u3099") end def test_move_to_beg_end input_keys('bcd') - assert_byte_pointer_size('bcd') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('bcd', '') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'bcd') input_keys('a') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(4) + assert_line_around_cursor('a', 'bcd') input_keys("\C-e", false) - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('abcd', '') input_keys('e') - assert_byte_pointer_size('abcde') - assert_cursor(5) - assert_cursor_max(5) - assert_line('abcde') + assert_line_around_cursor('abcde', '') end def test_ed_newline_with_cr input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') refute(@line_editor.finished?) input_keys("\C-m", false) - assert_line('ab') + assert_line_around_cursor('ab', '') assert(@line_editor.finished?) end def test_ed_newline_with_lf input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') refute(@line_editor.finished?) input_keys("\C-j", false) - assert_line('ab') + assert_line_around_cursor('ab', '') assert(@line_editor.finished?) end def test_em_delete_prev_char input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') input_keys("\C-h", false) - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(1) - assert_line('a') + assert_line_around_cursor('a', '') end def test_em_delete_prev_char_for_mbchar input_keys('かき') - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('かき', '') input_keys("\C-h", false) - assert_byte_pointer_size('か') - assert_cursor(2) - assert_cursor_max(2) - assert_line('か') + assert_line_around_cursor('か', '') end def test_em_delete_prev_char_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099") - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor("か\u3099き\u3099", '') input_keys("\C-h", false) - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(2) - assert_line("か\u3099") + assert_line_around_cursor("か\u3099", '') end def test_ed_quoted_insert input_keys("ab\C-v\C-acd") - assert_line("ab\C-acd") - assert_byte_pointer_size("ab\C-acd") - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor("ab\C-acd", '') input_keys("\C-q\C-b") - assert_line("ab\C-acd\C-b") - assert_byte_pointer_size("ab\C-acd\C-b") - assert_cursor(8) - assert_cursor_max(8) + assert_line_around_cursor("ab\C-acd\C-b", '') end def test_ed_kill_line input_keys("\C-k", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') input_keys("\C-k", false) - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('abc', '') input_keys("\C-b\C-k", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) - assert_line('ab') + assert_line_around_cursor('ab', '') end def test_em_kill_line @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') input_keys("\C-b", false) @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') input_keys("\C-a", false) @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_move_to_beg input_keys('abd') - assert_byte_pointer_size('abd') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abd', '') input_keys("\C-b", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'd') input_keys('c') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(4) + assert_line_around_cursor('abc', 'd') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) + assert_line_around_cursor('', 'abcd') input_keys('012') - assert_byte_pointer_size('012') - assert_cursor(3) - assert_cursor_max(7) - assert_line('012abcd') + assert_line_around_cursor('012', 'abcd') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) + assert_line_around_cursor('', '012abcd') input_keys('ABC') - assert_byte_pointer_size('ABC') - assert_cursor(3) - assert_cursor_max(10) - assert_line('ABC012abcd') + assert_line_around_cursor('ABC', '012abcd') input_keys("\C-f" * 10 + "\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(10) + assert_line_around_cursor('', 'ABC012abcd') input_keys('a') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(11) - assert_line('aABC012abcd') + assert_line_around_cursor('a', 'ABC012abcd') end def test_ed_move_to_beg_with_blank input_keys(' abc') - assert_byte_pointer_size(' abc') - assert_cursor(5) - assert_cursor_max(5) + assert_line_around_cursor(' abc', '') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) + assert_line_around_cursor('', ' abc') end def test_ed_move_to_end input_keys('abd') - assert_byte_pointer_size('abd') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abd', '') input_keys("\C-b", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'd') input_keys('c') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(4) + assert_line_around_cursor('abc', 'd') input_keys("\C-e", false) - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('abcd', '') input_keys('012') - assert_byte_pointer_size('abcd012') - assert_cursor(7) - assert_cursor_max(7) - assert_line('abcd012') + assert_line_around_cursor('abcd012', '') input_keys("\C-e", false) - assert_byte_pointer_size('abcd012') - assert_cursor(7) - assert_cursor_max(7) + assert_line_around_cursor('abcd012', '') input_keys('ABC') - assert_byte_pointer_size('abcd012ABC') - assert_cursor(10) - assert_cursor_max(10) - assert_line('abcd012ABC') + assert_line_around_cursor('abcd012ABC', '') input_keys("\C-b" * 10 + "\C-e", false) - assert_byte_pointer_size('abcd012ABC') - assert_cursor(10) - assert_cursor_max(10) + assert_line_around_cursor('abcd012ABC', '') input_keys('a') - assert_byte_pointer_size('abcd012ABCa') - assert_cursor(11) - assert_cursor_max(11) - assert_line('abcd012ABCa') + assert_line_around_cursor('abcd012ABCa', '') end def test_em_delete input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) + assert_line_around_cursor('', 'ab') input_keys("\C-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) - assert_line('b') + assert_line_around_cursor('', 'b') end def test_em_delete_for_mbchar input_keys('かき') - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('かき', '') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) + assert_line_around_cursor('', 'かき') input_keys("\C-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) - assert_line('き') + assert_line_around_cursor('', 'き') end def test_em_delete_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099") - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor("か\u3099き\u3099", '') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) + assert_line_around_cursor('', "か\u3099き\u3099") input_keys("\C-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) - assert_line("き\u3099") + assert_line_around_cursor('', "き\u3099") end def test_em_delete_ends_editing input_keys("\C-d") # quit from inputing - assert_line(nil) + assert_nil(@line_editor.line) assert(@line_editor.finished?) end @@ -444,834 +264,454 @@ def test_ed_clear_screen_with_inputed input_keys('abc') input_keys("\C-b", false) refute(@line_editor.instance_variable_get(:@cleared)) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'c') input_keys("\C-l", false) assert(@line_editor.instance_variable_get(:@cleared)) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('ab', 'c') end def test_key_delete input_keys('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') @line_editor.input_key(Reline::Key.new(:key_delete, :key_delete, false)) - assert_cursor(3) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('abc', '') end def test_key_delete_does_not_end_editing @line_editor.input_key(Reline::Key.new(:key_delete, :key_delete, false)) - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') refute(@line_editor.finished?) end def test_key_delete_preserves_cursor input_keys('abc') input_keys("\C-b", false) - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'c') @line_editor.input_key(Reline::Key.new(:key_delete, :key_delete, false)) - assert_cursor(2) - assert_cursor_max(2) - assert_line('ab') + assert_line_around_cursor('ab', '') end def test_em_next_word - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor('', '') input_keys('abc def{bbb}ccc') input_keys("\C-a\M-F", false) - assert_byte_pointer_size('abc') - assert_cursor(3) + assert_line_around_cursor('abc', ' def{bbb}ccc') input_keys("\M-F", false) - assert_byte_pointer_size('abc def') - assert_cursor(7) + assert_line_around_cursor('abc def', '{bbb}ccc') input_keys("\M-F", false) - assert_byte_pointer_size('abc def{bbb') - assert_cursor(11) + assert_line_around_cursor('abc def{bbb', '}ccc') input_keys("\M-F", false) - assert_byte_pointer_size('abc def{bbb}ccc') - assert_cursor(15) + assert_line_around_cursor('abc def{bbb}ccc', '') input_keys("\M-F", false) - assert_byte_pointer_size('abc def{bbb}ccc') - assert_cursor(15) + assert_line_around_cursor('abc def{bbb}ccc', '') end def test_em_next_word_for_mbchar - assert_cursor(0) + assert_line_around_cursor('', '') input_keys('あいう かきく{さしす}たちつ') input_keys("\C-a\M-F", false) - assert_byte_pointer_size('あいう') - assert_cursor(6) + assert_line_around_cursor('あいう', ' かきく{さしす}たちつ') input_keys("\M-F", false) - assert_byte_pointer_size('あいう かきく') - assert_cursor(13) + assert_line_around_cursor('あいう かきく', '{さしす}たちつ') input_keys("\M-F", false) - assert_byte_pointer_size('あいう かきく{さしす') - assert_cursor(20) + assert_line_around_cursor('あいう かきく{さしす', '}たちつ') input_keys("\M-F", false) - assert_byte_pointer_size('あいう かきく{さしす}たちつ') - assert_cursor(27) + assert_line_around_cursor('あいう かきく{さしす}たちつ', '') input_keys("\M-F", false) - assert_byte_pointer_size('あいう かきく{さしす}たちつ') - assert_cursor(27) + assert_line_around_cursor('あいう かきく{さしす}たちつ', '') end def test_em_next_word_for_mbchar_by_plural_code_points - assert_cursor(0) + assert_line_around_cursor("", "") input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\C-a\M-F", false) - assert_byte_pointer_size("あいう") - assert_cursor(6) + assert_line_around_cursor("あいう", " か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\M-F", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099") - assert_cursor(13) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099", "{さしす}たちつ") input_keys("\M-F", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす") - assert_cursor(20) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす", "}たちつ") input_keys("\M-F", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_cursor(27) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", "") input_keys("\M-F", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_cursor(27) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", "") end def test_em_prev_word input_keys('abc def{bbb}ccc') - assert_byte_pointer_size('abc def{bbb}ccc') - assert_cursor(15) + assert_line_around_cursor('abc def{bbb}ccc', '') input_keys("\M-B", false) - assert_byte_pointer_size('abc def{bbb}') - assert_cursor(12) + assert_line_around_cursor('abc def{bbb}', 'ccc') input_keys("\M-B", false) - assert_byte_pointer_size('abc def{') - assert_cursor(8) + assert_line_around_cursor('abc def{', 'bbb}ccc') input_keys("\M-B", false) - assert_byte_pointer_size('abc ') - assert_cursor(4) + assert_line_around_cursor('abc ', 'def{bbb}ccc') input_keys("\M-B", false) - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor('', 'abc def{bbb}ccc') input_keys("\M-B", false) - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor('', 'abc def{bbb}ccc') end def test_em_prev_word_for_mbchar input_keys('あいう かきく{さしす}たちつ') - assert_byte_pointer_size('あいう かきく{さしす}たちつ') - assert_cursor(27) + assert_line_around_cursor('あいう かきく{さしす}たちつ', '') input_keys("\M-B", false) - assert_byte_pointer_size('あいう かきく{さしす}') - assert_cursor(21) + assert_line_around_cursor('あいう かきく{さしす}', 'たちつ') input_keys("\M-B", false) - assert_byte_pointer_size('あいう かきく{') - assert_cursor(14) + assert_line_around_cursor('あいう かきく{', 'さしす}たちつ') input_keys("\M-B", false) - assert_byte_pointer_size('あいう ') - assert_cursor(7) + assert_line_around_cursor('あいう ', 'かきく{さしす}たちつ') input_keys("\M-B", false) - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor('', 'あいう かきく{さしす}たちつ') input_keys("\M-B", false) - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor('', 'あいう かきく{さしす}たちつ') end def test_em_prev_word_for_mbchar_by_plural_code_points input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_cursor(27) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", "") input_keys("\M-B", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}") - assert_cursor(21) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}", "たちつ") input_keys("\M-B", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{") - assert_cursor(14) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{", "さしす}たちつ") input_keys("\M-B", false) - assert_byte_pointer_size('あいう ') - assert_cursor(7) + assert_line_around_cursor("あいう ", "か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\M-B", false) - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor("", "あいう か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\M-B", false) - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor("", "あいう か\u3099き\u3099く\u3099{さしす}たちつ") end def test_em_delete_next_word input_keys('abc def{bbb}ccc') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(15) + assert_line_around_cursor('', 'abc def{bbb}ccc') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(12) - assert_line(' def{bbb}ccc') + assert_line_around_cursor('', ' def{bbb}ccc') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(8) - assert_line('{bbb}ccc') + assert_line_around_cursor('', '{bbb}ccc') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) - assert_line('}ccc') + assert_line_around_cursor('', '}ccc') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_em_delete_next_word_for_mbchar input_keys('あいう かきく{さしす}たちつ') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(27) + assert_line_around_cursor('', 'あいう かきく{さしす}たちつ') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(21) - assert_line(' かきく{さしす}たちつ') + assert_line_around_cursor('', ' かきく{さしす}たちつ') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(14) - assert_line('{さしす}たちつ') + assert_line_around_cursor('', '{さしす}たちつ') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) - assert_line('}たちつ') + assert_line_around_cursor('', '}たちつ') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_em_delete_next_word_for_mbchar_by_plural_code_points input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(27) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(27) + assert_line_around_cursor('', "あいう か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(21) - assert_line(" か\u3099き\u3099く\u3099{さしす}たちつ") + assert_line_around_cursor('', " か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(14) - assert_line('{さしす}たちつ') + assert_line_around_cursor('', '{さしす}たちつ') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) - assert_line('}たちつ') + assert_line_around_cursor('', '}たちつ') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_delete_prev_word input_keys('abc def{bbb}ccc') - assert_byte_pointer_size('abc def{bbb}ccc') - assert_cursor(15) - assert_cursor_max(15) + assert_line_around_cursor('abc def{bbb}ccc', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('abc def{bbb}') - assert_cursor(12) - assert_cursor_max(12) - assert_line('abc def{bbb}') + assert_line_around_cursor('abc def{bbb}', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('abc def{') - assert_cursor(8) - assert_cursor_max(8) - assert_line('abc def{') + assert_line_around_cursor('abc def{', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('abc ') - assert_cursor(4) - assert_cursor_max(4) - assert_line('abc ') + assert_line_around_cursor('abc ', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_delete_prev_word_for_mbchar input_keys('あいう かきく{さしす}たちつ') - assert_byte_pointer_size('あいう かきく{さしす}たちつ') - assert_cursor(27) - assert_cursor_max(27) + assert_line_around_cursor('あいう かきく{さしす}たちつ', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('あいう かきく{さしす}') - assert_cursor(21) - assert_cursor_max(21) - assert_line('あいう かきく{さしす}') + assert_line_around_cursor('あいう かきく{さしす}', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('あいう かきく{') - assert_cursor(14) - assert_cursor_max(14) - assert_line('あいう かきく{') + assert_line_around_cursor('あいう かきく{', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('あいう ') - assert_cursor(7) - assert_cursor_max(7) - assert_line('あいう ') + assert_line_around_cursor('あいう ', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_delete_prev_word_for_mbchar_by_plural_code_points input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_cursor(27) - assert_cursor_max(27) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", '') input_keys("\M-\C-H", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}") - assert_cursor(21) - assert_cursor_max(21) - assert_line("あいう か\u3099き\u3099く\u3099{さしす}") + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}", '') input_keys("\M-\C-H", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{") - assert_cursor(14) - assert_cursor_max(14) - assert_line("あいう か\u3099き\u3099く\u3099{") + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{", '') input_keys("\M-\C-H", false) - assert_byte_pointer_size("あいう ") - assert_cursor(7) - assert_cursor_max(7) - assert_line('あいう ') + assert_line_around_cursor('あいう ', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_transpose_chars input_keys('abc') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'abc') input_keys("\C-t", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('', 'abc') input_keys("\C-f\C-t", false) - assert_byte_pointer_size('ba') - assert_cursor(2) - assert_cursor_max(3) - assert_line('bac') + assert_line_around_cursor('ba', 'c') input_keys("\C-t", false) - assert_byte_pointer_size('bca') - assert_cursor(3) - assert_cursor_max(3) - assert_line('bca') + assert_line_around_cursor('bca', '') input_keys("\C-t", false) - assert_byte_pointer_size('bac') - assert_cursor(3) - assert_cursor_max(3) - assert_line('bac') + assert_line_around_cursor('bac', '') end def test_ed_transpose_chars_for_mbchar input_keys('あかさ') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'あかさ') input_keys("\C-t", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) - assert_line('あかさ') + assert_line_around_cursor('', 'あかさ') input_keys("\C-f\C-t", false) - assert_byte_pointer_size('かあ') - assert_cursor(4) - assert_cursor_max(6) - assert_line('かあさ') + assert_line_around_cursor('かあ', 'さ') input_keys("\C-t", false) - assert_byte_pointer_size('かさあ') - assert_cursor(6) - assert_cursor_max(6) - assert_line('かさあ') + assert_line_around_cursor('かさあ', '') input_keys("\C-t", false) - assert_byte_pointer_size('かあさ') - assert_cursor(6) - assert_cursor_max(6) - assert_line('かあさ') + assert_line_around_cursor('かあさ', '') end def test_ed_transpose_chars_for_mbchar_by_plural_code_points input_keys("あか\u3099さ") input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', "あか\u3099さ") input_keys("\C-t", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) - assert_line("あか\u3099さ") + assert_line_around_cursor('', "あか\u3099さ") input_keys("\C-f\C-t", false) - assert_byte_pointer_size("か\u3099あ") - assert_cursor(4) - assert_cursor_max(6) - assert_line("か\u3099あさ") + assert_line_around_cursor("か\u3099あ", 'さ') input_keys("\C-t", false) - assert_byte_pointer_size("か\u3099さあ") - assert_cursor(6) - assert_cursor_max(6) - assert_line("か\u3099さあ") + assert_line_around_cursor("か\u3099さあ", '') input_keys("\C-t", false) - assert_byte_pointer_size("か\u3099あさ") - assert_cursor(6) - assert_cursor_max(6) - assert_line("か\u3099あさ") + assert_line_around_cursor("か\u3099あさ", '') end def test_ed_transpose_words input_keys('abc def') - assert_line('abc def') - assert_byte_pointer_size('abc def') - assert_cursor(7) - assert_cursor_max(7) + assert_line_around_cursor('abc def', '') input_keys("\M-t", false) - assert_line('def abc') - assert_byte_pointer_size('def abc') - assert_cursor(7) - assert_cursor_max(7) + assert_line_around_cursor('def abc', '') input_keys("\C-a\C-k", false) input_keys(' abc def ') input_keys("\C-b" * 4, false) - assert_line(' abc def ') - assert_byte_pointer_size(' abc de') - assert_cursor(8) - assert_cursor_max(12) + assert_line_around_cursor(' abc de', 'f ') input_keys("\M-t", false) - assert_line(' def abc ') - assert_byte_pointer_size(' def abc') - assert_cursor(9) - assert_cursor_max(12) + assert_line_around_cursor(' def abc', ' ') input_keys("\C-a\C-k", false) input_keys(' abc def ') input_keys("\C-b" * 6, false) - assert_line(' abc def ') - assert_byte_pointer_size(' abc ') - assert_cursor(6) - assert_cursor_max(12) + assert_line_around_cursor(' abc ', 'def ') input_keys("\M-t", false) - assert_line(' def abc ') - assert_byte_pointer_size(' def abc') - assert_cursor(9) - assert_cursor_max(12) + assert_line_around_cursor(' def abc', ' ') input_keys("\M-t", false) - assert_line(' abc def') - assert_byte_pointer_size(' abc def') - assert_cursor(12) - assert_cursor_max(12) + assert_line_around_cursor(' abc def', '') end def test_ed_transpose_words_for_mbchar input_keys('あいう かきく') - assert_line('あいう かきく') - assert_byte_pointer_size('あいう かきく') - assert_cursor(13) - assert_cursor_max(13) + assert_line_around_cursor('あいう かきく', '') input_keys("\M-t", false) - assert_line('かきく あいう') - assert_byte_pointer_size('かきく あいう') - assert_cursor(13) - assert_cursor_max(13) + assert_line_around_cursor('かきく あいう', '') input_keys("\C-a\C-k", false) input_keys(' あいう かきく ') input_keys("\C-b" * 4, false) - assert_line(' あいう かきく ') - assert_byte_pointer_size(' あいう かき') - assert_cursor(13) - assert_cursor_max(18) + assert_line_around_cursor(' あいう かき', 'く ') input_keys("\M-t", false) - assert_line(' かきく あいう ') - assert_byte_pointer_size(' かきく あいう') - assert_cursor(15) - assert_cursor_max(18) + assert_line_around_cursor(' かきく あいう', ' ') input_keys("\C-a\C-k", false) input_keys(' あいう かきく ') input_keys("\C-b" * 6, false) - assert_line(' あいう かきく ') - assert_byte_pointer_size(' あいう ') - assert_cursor(9) - assert_cursor_max(18) + assert_line_around_cursor(' あいう ', 'かきく ') input_keys("\M-t", false) - assert_line(' かきく あいう ') - assert_byte_pointer_size(' かきく あいう') - assert_cursor(15) - assert_cursor_max(18) + assert_line_around_cursor(' かきく あいう', ' ') input_keys("\M-t", false) - assert_line(' あいう かきく') - assert_byte_pointer_size(' あいう かきく') - assert_cursor(18) - assert_cursor_max(18) + assert_line_around_cursor(' あいう かきく', '') end def test_ed_transpose_words_with_one_word input_keys('abc ') - assert_line('abc ') - assert_byte_pointer_size('abc ') - assert_cursor(5) - assert_cursor_max(5) + assert_line_around_cursor('abc ', '') input_keys("\M-t", false) - assert_line('abc ') - assert_byte_pointer_size('abc ') - assert_cursor(5) - assert_cursor_max(5) + assert_line_around_cursor('abc ', '') input_keys("\C-b", false) - assert_line('abc ') - assert_byte_pointer_size('abc ') - assert_cursor(4) - assert_cursor_max(5) + assert_line_around_cursor('abc ', ' ') input_keys("\M-t", false) - assert_line('abc ') - assert_byte_pointer_size('abc ') - assert_cursor(4) - assert_cursor_max(5) + assert_line_around_cursor('abc ', ' ') input_keys("\C-b" * 2, false) - assert_line('abc ') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(5) + assert_line_around_cursor('ab', 'c ') input_keys("\M-t", false) - assert_line('abc ') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(5) + assert_line_around_cursor('ab', 'c ') input_keys("\M-t", false) - assert_line('abc ') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(5) + assert_line_around_cursor('ab', 'c ') end def test_ed_transpose_words_with_one_word_for_mbchar input_keys('あいう ') - assert_line('あいう ') - assert_byte_pointer_size('あいう ') - assert_cursor(8) - assert_cursor_max(8) + assert_line_around_cursor('あいう ', '') input_keys("\M-t", false) - assert_line('あいう ') - assert_byte_pointer_size('あいう ') - assert_cursor(8) - assert_cursor_max(8) + assert_line_around_cursor('あいう ', '') input_keys("\C-b", false) - assert_line('あいう ') - assert_byte_pointer_size('あいう ') - assert_cursor(7) - assert_cursor_max(8) + assert_line_around_cursor('あいう ', ' ') input_keys("\M-t", false) - assert_line('あいう ') - assert_byte_pointer_size('あいう ') - assert_cursor(7) - assert_cursor_max(8) + assert_line_around_cursor('あいう ', ' ') input_keys("\C-b" * 2, false) - assert_line('あいう ') - assert_byte_pointer_size('あい') - assert_cursor(4) - assert_cursor_max(8) + assert_line_around_cursor('あい', 'う ') input_keys("\M-t", false) - assert_line('あいう ') - assert_byte_pointer_size('あい') - assert_cursor(4) - assert_cursor_max(8) + assert_line_around_cursor('あい', 'う ') input_keys("\M-t", false) - assert_line('あいう ') - assert_byte_pointer_size('あい') - assert_cursor(4) - assert_cursor_max(8) + assert_line_around_cursor('あい', 'う ') end def test_ed_digit input_keys('0123') - assert_byte_pointer_size('0123') - assert_cursor(4) - assert_cursor_max(4) - assert_line('0123') + assert_line_around_cursor('0123', '') end def test_ed_next_and_prev_char input_keys('abc') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') input_keys("\C-b", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'c') input_keys("\C-b", false) - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) + assert_line_around_cursor('a', 'bc') input_keys("\C-b", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'abc') input_keys("\C-b", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'abc') input_keys("\C-f", false) - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) + assert_line_around_cursor('a', 'bc') input_keys("\C-f", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'c') input_keys("\C-f", false) - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') input_keys("\C-f", false) - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') end def test_ed_next_and_prev_char_for_mbchar input_keys('あいう') - assert_byte_pointer_size('あいう') - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor('あいう', '') input_keys("\C-b", false) - assert_byte_pointer_size('あい') - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor('あい', 'う') input_keys("\C-b", false) - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor('あ', 'いう') input_keys("\C-b", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'あいう') input_keys("\C-b", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'あいう') input_keys("\C-f", false) - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor('あ', 'いう') input_keys("\C-f", false) - assert_byte_pointer_size('あい') - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor('あい', 'う') input_keys("\C-f", false) - assert_byte_pointer_size('あいう') - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor('あいう', '') input_keys("\C-f", false) - assert_byte_pointer_size('あいう') - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor('あいう', '') end def test_ed_next_and_prev_char_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099く\u3099") - assert_byte_pointer_size("か\u3099き\u3099く\u3099") - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099く\u3099", '') input_keys("\C-b", false) - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099", "く\u3099") input_keys("\C-b", false) - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099", "き\u3099く\u3099") input_keys("\C-b", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', "か\u3099き\u3099く\u3099") input_keys("\C-b", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', "か\u3099き\u3099く\u3099") input_keys("\C-f", false) - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099", "き\u3099く\u3099") input_keys("\C-f", false) - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099", "く\u3099") input_keys("\C-f", false) - assert_byte_pointer_size("か\u3099き\u3099く\u3099") - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099く\u3099", '') input_keys("\C-f", false) - assert_byte_pointer_size("か\u3099き\u3099く\u3099") - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099く\u3099", '') end def test_em_capitol_case input_keys('abc def{bbb}ccc') input_keys("\C-a\M-c", false) - assert_byte_pointer_size('Abc') - assert_cursor(3) - assert_cursor_max(15) - assert_line('Abc def{bbb}ccc') + assert_line_around_cursor('Abc', ' def{bbb}ccc') input_keys("\M-c", false) - assert_byte_pointer_size('Abc Def') - assert_cursor(7) - assert_cursor_max(15) - assert_line('Abc Def{bbb}ccc') + assert_line_around_cursor('Abc Def', '{bbb}ccc') input_keys("\M-c", false) - assert_byte_pointer_size('Abc Def{Bbb') - assert_cursor(11) - assert_cursor_max(15) - assert_line('Abc Def{Bbb}ccc') + assert_line_around_cursor('Abc Def{Bbb', '}ccc') input_keys("\M-c", false) - assert_byte_pointer_size('Abc Def{Bbb}Ccc') - assert_cursor(15) - assert_cursor_max(15) - assert_line('Abc Def{Bbb}Ccc') + assert_line_around_cursor('Abc Def{Bbb}Ccc', '') end def test_em_capitol_case_with_complex_example input_keys('{}#* AaA!!!cCc ') input_keys("\C-a\M-c", false) - assert_byte_pointer_size('{}#* Aaa') - assert_cursor(11) - assert_cursor_max(20) - assert_line('{}#* Aaa!!!cCc ') + assert_line_around_cursor('{}#* Aaa', '!!!cCc ') input_keys("\M-c", false) - assert_byte_pointer_size('{}#* Aaa!!!Ccc') - assert_cursor(17) - assert_cursor_max(20) - assert_line('{}#* Aaa!!!Ccc ') + assert_line_around_cursor('{}#* Aaa!!!Ccc', ' ') input_keys("\M-c", false) - assert_byte_pointer_size('{}#* Aaa!!!Ccc ') - assert_cursor(20) - assert_cursor_max(20) - assert_line('{}#* Aaa!!!Ccc ') + assert_line_around_cursor('{}#* Aaa!!!Ccc ', '') end def test_em_lower_case input_keys('AbC def{bBb}CCC') input_keys("\C-a\M-l", false) - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(15) - assert_line('abc def{bBb}CCC') + assert_line_around_cursor('abc', ' def{bBb}CCC') input_keys("\M-l", false) - assert_byte_pointer_size('abc def') - assert_cursor(7) - assert_cursor_max(15) - assert_line('abc def{bBb}CCC') + assert_line_around_cursor('abc def', '{bBb}CCC') input_keys("\M-l", false) - assert_byte_pointer_size('abc def{bbb') - assert_cursor(11) - assert_cursor_max(15) - assert_line('abc def{bbb}CCC') + assert_line_around_cursor('abc def{bbb', '}CCC') input_keys("\M-l", false) - assert_byte_pointer_size('abc def{bbb}ccc') - assert_cursor(15) - assert_cursor_max(15) - assert_line('abc def{bbb}ccc') + assert_line_around_cursor('abc def{bbb}ccc', '') end def test_em_lower_case_with_complex_example input_keys('{}#* AaA!!!cCc ') input_keys("\C-a\M-l", false) - assert_byte_pointer_size('{}#* aaa') - assert_cursor(11) - assert_cursor_max(20) - assert_line('{}#* aaa!!!cCc ') + assert_line_around_cursor('{}#* aaa', '!!!cCc ') input_keys("\M-l", false) - assert_byte_pointer_size('{}#* aaa!!!ccc') - assert_cursor(17) - assert_cursor_max(20) - assert_line('{}#* aaa!!!ccc ') + assert_line_around_cursor('{}#* aaa!!!ccc', ' ') input_keys("\M-l", false) - assert_byte_pointer_size('{}#* aaa!!!ccc ') - assert_cursor(20) - assert_cursor_max(20) - assert_line('{}#* aaa!!!ccc ') + assert_line_around_cursor('{}#* aaa!!!ccc ', '') end def test_em_upper_case input_keys('AbC def{bBb}CCC') input_keys("\C-a\M-u", false) - assert_byte_pointer_size('ABC') - assert_cursor(3) - assert_cursor_max(15) - assert_line('ABC def{bBb}CCC') + assert_line_around_cursor('ABC', ' def{bBb}CCC') input_keys("\M-u", false) - assert_byte_pointer_size('ABC DEF') - assert_cursor(7) - assert_cursor_max(15) - assert_line('ABC DEF{bBb}CCC') + assert_line_around_cursor('ABC DEF', '{bBb}CCC') input_keys("\M-u", false) - assert_byte_pointer_size('ABC DEF{BBB') - assert_cursor(11) - assert_cursor_max(15) - assert_line('ABC DEF{BBB}CCC') + assert_line_around_cursor('ABC DEF{BBB', '}CCC') input_keys("\M-u", false) - assert_byte_pointer_size('ABC DEF{BBB}CCC') - assert_cursor(15) - assert_cursor_max(15) - assert_line('ABC DEF{BBB}CCC') + assert_line_around_cursor('ABC DEF{BBB}CCC', '') end def test_em_upper_case_with_complex_example input_keys('{}#* AaA!!!cCc ') input_keys("\C-a\M-u", false) - assert_byte_pointer_size('{}#* AAA') - assert_cursor(11) - assert_cursor_max(20) - assert_line('{}#* AAA!!!cCc ') + assert_line_around_cursor('{}#* AAA', '!!!cCc ') input_keys("\M-u", false) - assert_byte_pointer_size('{}#* AAA!!!CCC') - assert_cursor(17) - assert_cursor_max(20) - assert_line('{}#* AAA!!!CCC ') + assert_line_around_cursor('{}#* AAA!!!CCC', ' ') input_keys("\M-u", false) - assert_byte_pointer_size('{}#* AAA!!!CCC ') - assert_cursor(20) - assert_cursor_max(20) - assert_line('{}#* AAA!!!CCC ') + assert_line_around_cursor('{}#* AAA!!!CCC ', '') end def test_em_delete_or_list @@ -1286,28 +726,16 @@ def test_em_delete_or_list } } input_keys('fooo') - assert_byte_pointer_size('fooo') - assert_cursor(4) - assert_cursor_max(4) - assert_line('fooo') + assert_line_around_cursor('fooo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-b", false) - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(4) - assert_line('fooo') + assert_line_around_cursor('foo', 'o') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) @line_editor.input_key(Reline::Key.new(:em_delete_or_list, :em_delete_or_list, false)) - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) @line_editor.input_key(Reline::Key.new(:em_delete_or_list, :em_delete_or_list, false)) - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) end @@ -1322,22 +750,13 @@ def test_completion_duplicated_list } } input_keys('foo_') - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(%w{foo_foo foo_bar}, @line_editor.instance_variable_get(:@menu_info).list) end @@ -1353,36 +772,21 @@ def test_completion } } input_keys('fo') - assert_byte_pointer_size('fo') - assert_cursor(2) - assert_cursor_max(2) - assert_line('fo') + assert_line_around_cursor('fo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) input_keys('a') input_keys("\C-i", false) - assert_byte_pointer_size('foo_a') - assert_cursor(5) - assert_cursor_max(5) - assert_line('foo_a') + assert_line_around_cursor('foo_a', '') input_keys("\C-h", false) input_keys('b') input_keys("\C-i", false) - assert_byte_pointer_size('foo_ba') - assert_cursor(6) - assert_cursor_max(6) - assert_line('foo_ba') + assert_line_around_cursor('foo_ba', '') end def test_completion_with_indent @@ -1397,22 +801,13 @@ def test_completion_with_indent } } input_keys(' fo') - assert_byte_pointer_size(' fo') - assert_cursor(4) - assert_cursor_max(4) - assert_line(' fo') + assert_line_around_cursor(' fo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size(' foo_') - assert_cursor(6) - assert_cursor_max(6) - assert_line(' foo_') + assert_line_around_cursor(' foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size(' foo_') - assert_cursor(6) - assert_cursor_max(6) - assert_line(' foo_') + assert_line_around_cursor(' foo_', '') assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) end @@ -1428,22 +823,13 @@ def test_completion_with_indent_and_completer_quote_characters } } input_keys(' "".fo') - assert_byte_pointer_size(' "".fo') - assert_cursor(7) - assert_cursor_max(7) - assert_line(' "".fo') + assert_line_around_cursor(' "".fo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size(' "".foo_') - assert_cursor(9) - assert_cursor_max(9) - assert_line(' "".foo_') + assert_line_around_cursor(' "".foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size(' "".foo_') - assert_cursor(9) - assert_cursor_max(9) - assert_line(' "".foo_') + assert_line_around_cursor(' "".foo_', '') assert_equal(%w{"".foo_foo "".foo_bar "".foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) end @@ -1461,54 +847,33 @@ def test_completion_with_perfect_match matched = m } input_keys('fo') - assert_byte_pointer_size('fo') - assert_cursor(2) - assert_cursor_max(2) - assert_line('fo') + assert_line_around_cursor('fo', '') assert_equal(Reline::LineEditor::CompletionState::NORMAL, @line_editor.instance_variable_get(:@completion_state)) assert_equal(nil, matched) input_keys("\C-i", false) - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') assert_equal(Reline::LineEditor::CompletionState::MENU_WITH_PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) assert_equal(nil, matched) input_keys("\C-i", false) - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) assert_equal(nil, matched) input_keys("\C-i", false) - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) assert_equal('foo', matched) matched = nil input_keys('_') input_keys("\C-i", false) - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') assert_equal(Reline::LineEditor::CompletionState::MENU_WITH_PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) assert_equal(nil, matched) input_keys("\C-i", false) - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) assert_equal(nil, matched) input_keys("\C-i", false) - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) assert_equal('foo_bar', matched) end @@ -1525,43 +890,25 @@ def test_completion_with_completion_ignore_case } } input_keys('fo') - assert_byte_pointer_size('fo') - assert_cursor(2) - assert_cursor_max(2) - assert_line('fo') + assert_line_around_cursor('fo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(%w{foo_foo foo_bar}, @line_editor.instance_variable_get(:@menu_info).list) @config.completion_ignore_case = true input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(%w{foo_foo foo_bar Foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) input_keys('a') input_keys("\C-i", false) - assert_byte_pointer_size('foo_a') - assert_cursor(5) - assert_cursor_max(5) - assert_line('foo_a') + assert_line_around_cursor('foo_a', '') input_keys("\C-h", false) input_keys('b') input_keys("\C-i", false) - assert_byte_pointer_size('foo_ba') - assert_cursor(6) - assert_cursor_max(6) - assert_line('foo_ba') + assert_line_around_cursor('foo_ba', '') end def test_completion_in_middle_of_line @@ -1576,17 +923,11 @@ def test_completion_in_middle_of_line } } input_keys('abcde fo ABCDE') - assert_line('abcde fo ABCDE') + assert_line_around_cursor('abcde fo ABCDE', '') input_keys("\C-b" * 6 + "\C-i", false) - assert_byte_pointer_size('abcde foo_') - assert_cursor(10) - assert_cursor_max(16) - assert_line('abcde foo_ ABCDE') + assert_line_around_cursor('abcde foo_', ' ABCDE') input_keys("\C-b" * 2 + "\C-i", false) - assert_byte_pointer_size('abcde foo_') - assert_cursor(10) - assert_cursor_max(18) - assert_line('abcde foo_o_ ABCDE') + assert_line_around_cursor('abcde foo_', 'o_ ABCDE') end def test_completion_with_nil_value @@ -1602,125 +943,65 @@ def test_completion_with_nil_value } @config.completion_ignore_case = true input_keys('fo') - assert_byte_pointer_size('fo') - assert_cursor(2) - assert_cursor_max(2) - assert_line('fo') + assert_line_around_cursor('fo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(%w{foo_foo foo_bar Foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) input_keys('a') input_keys("\C-i", false) - assert_byte_pointer_size('foo_a') - assert_cursor(5) - assert_cursor_max(5) - assert_line('foo_a') + assert_line_around_cursor('foo_a', '') input_keys("\C-h", false) input_keys('b') input_keys("\C-i", false) - assert_byte_pointer_size('foo_ba') - assert_cursor(6) - assert_cursor_max(6) - assert_line('foo_ba') + assert_line_around_cursor('foo_ba', '') end def test_em_kill_region input_keys('abc def{bbb}ccc ddd ') - assert_byte_pointer_size('abc def{bbb}ccc ddd ') - assert_cursor(26) - assert_cursor_max(26) - assert_line('abc def{bbb}ccc ddd ') + assert_line_around_cursor('abc def{bbb}ccc ddd ', '') input_keys("\C-w", false) - assert_byte_pointer_size('abc def{bbb}ccc ') - assert_cursor(20) - assert_cursor_max(20) - assert_line('abc def{bbb}ccc ') + assert_line_around_cursor('abc def{bbb}ccc ', '') input_keys("\C-w", false) - assert_byte_pointer_size('abc ') - assert_cursor(6) - assert_cursor_max(6) - assert_line('abc ') + assert_line_around_cursor('abc ', '') input_keys("\C-w", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys("\C-w", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_em_kill_region_mbchar input_keys('あ い う{う}う ') - assert_byte_pointer_size('あ い う{う}う ') - assert_cursor(21) - assert_cursor_max(21) - assert_line('あ い う{う}う ') + assert_line_around_cursor('あ い う{う}う ', '') input_keys("\C-w", false) - assert_byte_pointer_size('あ い ') - assert_cursor(10) - assert_cursor_max(10) - assert_line('あ い ') + assert_line_around_cursor('あ い ', '') input_keys("\C-w", false) - assert_byte_pointer_size('あ ') - assert_cursor(5) - assert_cursor_max(5) - assert_line('あ ') + assert_line_around_cursor('あ ', '') input_keys("\C-w", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_vi_search_prev Reline::HISTORY.concat(%w{abc 123 AAA}) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-ra\C-j") - assert_line('abc') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'abc') end def test_larger_histories_than_history_size history_size = @config.history_size @config.history_size = 2 Reline::HISTORY.concat(%w{abc 123 AAA}) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-p") - assert_line('AAA') - assert_byte_pointer_size('AAA') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('AAA', '') input_keys("\C-p") - assert_line('123') - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('123', '') input_keys("\C-p") - assert_line('123') - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('123', '') ensure @config.history_size = history_size end @@ -1731,25 +1012,13 @@ def test_search_history_to_back '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r123") - assert_line('1234') - assert_byte_pointer_size('1234') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1234', '') input_keys("\C-ha") - assert_line('12aa') - assert_byte_pointer_size('12aa') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('12aa', '') input_keys("\C-h3") - assert_line('1235') - assert_byte_pointer_size('1235') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1235', '') end def test_search_history_to_front @@ -1758,25 +1027,13 @@ def test_search_history_to_front '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-s123") - assert_line('1235') - assert_byte_pointer_size('1235') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1235', '') input_keys("\C-ha") - assert_line('12aa') - assert_byte_pointer_size('12aa') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('12aa', '') input_keys("\C-h3") - assert_line('1234') - assert_byte_pointer_size('1234') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1234', '') end def test_search_history_front_and_back @@ -1785,30 +1042,15 @@ def test_search_history_front_and_back '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-s12") - assert_line('1235') - assert_byte_pointer_size('1235') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1235', '') input_keys("\C-s") - assert_line('12aa') - assert_byte_pointer_size('12aa') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('12aa', '') input_keys("\C-r") - assert_line('12aa') - assert_byte_pointer_size('12aa') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('12aa', '') input_keys("\C-r") - assert_line('1235') - assert_byte_pointer_size('1235') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1235', '') end def test_search_history_back_and_front @@ -1817,30 +1059,15 @@ def test_search_history_back_and_front '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r12") - assert_line('1234') - assert_byte_pointer_size('1234') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1234', '') input_keys("\C-r") - assert_line('12aa') - assert_byte_pointer_size('12aa') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('12aa', '') input_keys("\C-s") - assert_line('12aa') - assert_byte_pointer_size('12aa') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('12aa', '') input_keys("\C-s") - assert_line('1234') - assert_byte_pointer_size('1234') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1234', '') end def test_search_history_to_back_in_the_middle_of_histories @@ -1849,20 +1076,11 @@ def test_search_history_to_back_in_the_middle_of_histories '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-p\C-p") - assert_line('12aa') - assert_byte_pointer_size('12aa') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('12aa', '') input_keys("\C-r123") - assert_line('1235') - assert_byte_pointer_size('1235') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1235', '') end def test_search_history_twice @@ -1871,20 +1089,11 @@ def test_search_history_twice '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r123") - assert_line('1234') - assert_byte_pointer_size('1234') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1234', '') input_keys("\C-r") - assert_line('1235') - assert_byte_pointer_size('1235') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1235', '') end def test_search_history_by_last_determined @@ -1893,35 +1102,17 @@ def test_search_history_by_last_determined '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r123") - assert_line('1234') - assert_byte_pointer_size('1234') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1234', '') input_keys("\C-j") - assert_line('1234') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) + assert_line_around_cursor('', '1234') input_keys("\C-k") # delete - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r") - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r") - assert_line('1235') - assert_byte_pointer_size('1235') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1235', '') end def test_search_history_with_isearch_terminator @@ -1933,76 +1124,40 @@ def test_search_history_with_isearch_terminator '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r12a") - assert_line('12aa') - assert_byte_pointer_size('12aa') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('12aa', '') input_keys('Y') - assert_line('12aa') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) + assert_line_around_cursor('', '12aa') input_keys('x') - assert_line('x12aa') - assert_byte_pointer_size('x') - assert_cursor(1) - assert_cursor_max(5) + assert_line_around_cursor('x', '12aa') end def test_em_set_mark_and_em_exchange_mark input_keys('aaa bbb ccc ddd') - assert_byte_pointer_size('aaa bbb ccc ddd') - assert_cursor(15) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa bbb ccc ddd', '') input_keys("\C-a\M-F\M-F", false) - assert_byte_pointer_size('aaa bbb') - assert_cursor(7) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa bbb', ' ccc ddd') assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer)) input_keys("\x00", false) # C-Space - assert_byte_pointer_size('aaa bbb') - assert_cursor(7) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa bbb', ' ccc ddd') assert_equal([7, 0], @line_editor.instance_variable_get(:@mark_pointer)) input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('', 'aaa bbb ccc ddd') assert_equal([7, 0], @line_editor.instance_variable_get(:@mark_pointer)) input_key_by_symbol(:em_exchange_mark) - assert_byte_pointer_size('aaa bbb') - assert_cursor(7) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa bbb', ' ccc ddd') assert_equal([0, 0], @line_editor.instance_variable_get(:@mark_pointer)) end def test_em_exchange_mark_without_mark input_keys('aaa bbb ccc ddd') - assert_byte_pointer_size('aaa bbb ccc ddd') - assert_cursor(15) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa bbb ccc ddd', '') input_keys("\C-a\M-f", false) - assert_byte_pointer_size('aaa') - assert_cursor(3) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa', ' bbb ccc ddd') assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer)) input_key_by_symbol(:em_exchange_mark) - assert_byte_pointer_size('aaa') - assert_cursor(3) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa', ' bbb ccc ddd') assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer)) end @@ -2031,20 +1186,11 @@ def test_ed_search_prev_history input_keys('123') # The ed_search_prev_history doesn't have default binding @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12345') + assert_line_around_cursor('123', '45') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12356') + assert_line_around_cursor('123', '56') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12356') + assert_line_around_cursor('123', '56') end def test_ed_search_prev_history_with_empty @@ -2055,25 +1201,13 @@ def test_ed_search_prev_history_with_empty ]) # The ed_search_prev_history doesn't have default binding @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12345') + assert_line_around_cursor('', '12345') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12aaa') + assert_line_around_cursor('', '12aaa') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12356') + assert_line_around_cursor('', '12356') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12356') + assert_line_around_cursor('', '12356') end def test_ed_search_prev_history_without_match @@ -2085,10 +1219,7 @@ def test_ed_search_prev_history_without_match input_keys('ABC') # The ed_search_prev_history doesn't have default binding @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('ABC') - assert_cursor(3) - assert_cursor_max(3) - assert_line('ABC') + assert_line_around_cursor('ABC', '') end def test_ed_search_next_history @@ -2100,30 +1231,15 @@ def test_ed_search_next_history input_keys('123') # The ed_search_prev_history and ed_search_next_history doesn't have default binding @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12345') + assert_line_around_cursor('123', '45') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12356') + assert_line_around_cursor('123', '56') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12356') + assert_line_around_cursor('123', '56') @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12345') + assert_line_around_cursor('123', '45') @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12345') + assert_line_around_cursor('123', '45') end def test_ed_search_next_history_with_empty @@ -2134,35 +1250,17 @@ def test_ed_search_next_history_with_empty ]) # The ed_search_prev_history and ed_search_next_history doesn't have default binding @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12345') + assert_line_around_cursor('', '12345') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12aaa') + assert_line_around_cursor('', '12aaa') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12356') + assert_line_around_cursor('', '12356') @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12aaa') + assert_line_around_cursor('', '12aaa') @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12345') + assert_line_around_cursor('', '12345') @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end # Unicode emoji test @@ -2170,97 +1268,49 @@ def test_ed_insert_for_include_zwj_emoji omit "This test is for UTF-8 but the locale is #{Reline.core.encoding}" if Reline.core.encoding != Encoding::UTF_8 # U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466 is family: man, woman, girl, boy "👨‍👩‍👧‍👦" input_keys("\u{1F468}") # U+1F468 is man "👨" - assert_line("\u{1F468}") - assert_byte_pointer_size("\u{1F468}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨', '') input_keys("\u200D") # U+200D is ZERO WIDTH JOINER - assert_line("\u{1F468 200D}") - assert_byte_pointer_size("\u{1F468 200D}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨‍', '') input_keys("\u{1F469}") # U+1F469 is woman "👩" - assert_line("\u{1F468 200D 1F469}") - assert_byte_pointer_size("\u{1F468 200D 1F469}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨‍👩', '') input_keys("\u200D") # U+200D is ZERO WIDTH JOINER - assert_line("\u{1F468 200D 1F469 200D}") - assert_byte_pointer_size("\u{1F468 200D 1F469 200D}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨‍👩‍', '') input_keys("\u{1F467}") # U+1F467 is girl "👧" - assert_line("\u{1F468 200D 1F469 200D 1F467}") - assert_byte_pointer_size("\u{1F468 200D 1F469 200D 1F467}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨‍👩‍👧', '') input_keys("\u200D") # U+200D is ZERO WIDTH JOINER - assert_line("\u{1F468 200D 1F469 200D 1F467 200D}") - assert_byte_pointer_size("\u{1F468 200D 1F469 200D 1F467 200D}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨‍👩‍👧‍', '') input_keys("\u{1F466}") # U+1F466 is boy "👦" - assert_line("\u{1F468 200D 1F469 200D 1F467 200D 1F466}") - assert_byte_pointer_size("\u{1F468 200D 1F469 200D 1F467 200D 1F466}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨‍👩‍👧‍👦', '') # U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466 is family: man, woman, girl, boy "👨‍👩‍👧‍👦" input_keys("\u{1F468 200D 1F469 200D 1F467 200D 1F466}") - assert_line("\u{1F468 200D 1F469 200D 1F467 200D 1F466 1F468 200D 1F469 200D 1F467 200D 1F466}") - assert_byte_pointer_size("\u{1F468 200D 1F469 200D 1F467 200D 1F466 1F468 200D 1F469 200D 1F467 200D 1F466}") - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('👨‍👩‍👧‍👦👨‍👩‍👧‍👦', '') end def test_ed_insert_for_include_valiation_selector omit "This test is for UTF-8 but the locale is #{Reline.core.encoding}" if Reline.core.encoding != Encoding::UTF_8 # U+0030 U+FE00 is DIGIT ZERO + VARIATION SELECTOR-1 "0︀" input_keys("\u0030") # U+0030 is DIGIT ZERO - assert_line("\u0030") - assert_byte_pointer_size("\u0030") - assert_cursor(1) - assert_cursor_max(1) + assert_line_around_cursor('0', '') input_keys("\uFE00") # U+FE00 is VARIATION SELECTOR-1 - assert_line("\u{0030 FE00}") - assert_byte_pointer_size("\u{0030 FE00}") - assert_cursor(1) - assert_cursor_max(1) + assert_line_around_cursor('0︀', '') end def test_em_yank_pop input_keys("def hoge\C-w\C-b\C-f\C-w", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys("\C-y", false) - assert_byte_pointer_size('def ') - assert_cursor(4) - assert_cursor_max(4) - assert_line('def ') + assert_line_around_cursor('def ', '') input_keys("\M-\C-y", false) - assert_byte_pointer_size('hoge') - assert_cursor(4) - assert_cursor_max(4) - assert_line('hoge') + assert_line_around_cursor('hoge', '') end def test_em_kill_region_with_kill_ring input_keys("def hoge\C-b\C-b\C-b\C-b", false) - assert_byte_pointer_size('def ') - assert_cursor(4) - assert_cursor_max(8) - assert_line('def hoge') + assert_line_around_cursor('def ', 'hoge') input_keys("\C-k\C-w", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys("\C-y", false) - assert_byte_pointer_size('def hoge') - assert_cursor(8) - assert_cursor_max(8) - assert_line('def hoge') + assert_line_around_cursor('def hoge', '') end def test_ed_search_prev_next_history_in_multibyte @@ -2276,104 +1326,60 @@ def test_ed_search_prev_next_history_in_multibyte assert_whole_lines(['def foo', ' 12345', 'end']) assert_line_index(1) assert_whole_lines(['def foo', ' 12345', 'end']) - assert_byte_pointer_size(' 123') - assert_cursor(5) - assert_cursor_max(7) - assert_line(' 12345') + assert_line_around_cursor(' 123', '45') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) assert_line_index(2) assert_whole_lines(['def hoge', ' 67890', ' 12345', 'end']) - assert_byte_pointer_size(' 123') - assert_cursor(5) - assert_cursor_max(7) - assert_line(' 12345') + assert_line_around_cursor(' 123', '45') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) assert_line_index(2) assert_whole_lines(['def hoge', ' 67890', ' 12345', 'end']) - assert_byte_pointer_size(' 123') - assert_cursor(5) - assert_cursor_max(7) - assert_line(' 12345') + assert_line_around_cursor(' 123', '45') @line_editor.__send__(:ed_search_next_history, "\C-n".ord) assert_line_index(1) assert_whole_lines(['def foo', ' 12345', 'end']) - assert_byte_pointer_size(' 123') - assert_cursor(5) - assert_cursor_max(7) - assert_line(' 12345') + assert_line_around_cursor(' 123', '45') @line_editor.__send__(:ed_search_next_history, "\C-n".ord) assert_line_index(1) assert_whole_lines(['def foo', ' 12345', 'end']) - assert_byte_pointer_size(' 123') - assert_cursor(5) - assert_cursor_max(7) - assert_line(' 12345') + assert_line_around_cursor(' 123', '45') end def test_ignore_NUL_by_ed_quoted_insert input_keys(%Q{"\C-v\C-@"}, false) - assert_byte_pointer_size('""') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('""', '') end def test_ed_argument_digit_by_meta_num input_keys('abcdef') - assert_byte_pointer_size('abcdef') - assert_cursor(6) - assert_cursor_max(6) - assert_line('abcdef') + assert_line_around_cursor('abcdef', '') input_keys("\M-2", false) input_keys("\C-h", false) - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(4) - assert_line('abcd') + assert_line_around_cursor('abcd', '') end def test_halfwidth_kana_width_dakuten input_raw_keys('ガギゲゴ') - assert_byte_pointer_size('ガギゲゴ') - assert_cursor(8) - assert_cursor_max(8) + assert_line_around_cursor('ガギゲゴ', '') input_keys("\C-b\C-b", false) - assert_byte_pointer_size('ガギ') - assert_cursor(4) - assert_cursor_max(8) + assert_line_around_cursor('ガギ', 'ゲゴ') input_raw_keys('グ', false) - assert_byte_pointer_size('ガギグ') - assert_cursor(6) - assert_cursor_max(10) - assert_line('ガギグゲゴ') + assert_line_around_cursor('ガギグ', 'ゲゴ') end def test_input_unknown_char input_keys('͸') # U+0378 (unassigned) - assert_line('͸') - assert_byte_pointer_size('͸') - assert_cursor(1) - assert_cursor_max(1) + assert_line_around_cursor('͸', '') end def test_unix_line_discard input_keys("\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') input_keys("\C-b\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) - assert_line('c') + assert_line_around_cursor('', 'c') input_keys("\C-f\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end end diff --git a/test/reline/test_key_actor_vi.rb b/test/reline/test_key_actor_vi.rb index 7c924d19633bf8..91cbd49d74bfd5 100644 --- a/test/reline/test_key_actor_vi.rb +++ b/test/reline/test_key_actor_vi.rb @@ -25,950 +25,513 @@ def test_vi_command_mode def test_vi_command_mode_with_input input_keys("abc\C-[") assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) - assert_line('abc') + assert_line_around_cursor('ab', 'c') end def test_vi_insert assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) input_keys('i') - assert_line('i') - assert_cursor(1) + assert_line_around_cursor('i', '') assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) input_keys("\C-[") - assert_line('i') - assert_cursor(0) + assert_line_around_cursor('', 'i') assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) input_keys('i') - assert_line('i') - assert_cursor(0) + assert_line_around_cursor('', 'i') assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) end def test_vi_add assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) input_keys('a') - assert_line('a') - assert_cursor(1) + assert_line_around_cursor('a', '') assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) input_keys("\C-[") - assert_line('a') - assert_cursor(0) + assert_line_around_cursor('', 'a') assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) input_keys('a') - assert_line('a') - assert_cursor(1) + assert_line_around_cursor('a', '') assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) end def test_vi_insert_at_bol input_keys('I') - assert_line('I') + assert_line_around_cursor('I', '') assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) input_keys("12345\C-[hh") - assert_line('I12345') - assert_byte_pointer_size('I12') - assert_cursor(3) - assert_cursor_max(6) + assert_line_around_cursor('I12', '345') assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) input_keys('I') - assert_line('I12345') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'I12345') assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) end def test_vi_add_at_eol input_keys('A') - assert_line('A') + assert_line_around_cursor('A', '') assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) input_keys("12345\C-[hh") - assert_line('A12345') - assert_byte_pointer_size('A12') - assert_cursor(3) - assert_cursor_max(6) + assert_line_around_cursor('A12', '345') assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) input_keys('A') - assert_line('A12345') - assert_byte_pointer_size('A12345') - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor('A12345', '') assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) end def test_ed_insert_one input_keys('a') - assert_line('a') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(1) + assert_line_around_cursor('a', '') end def test_ed_insert_two input_keys('ab') - assert_line('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') end def test_ed_insert_mbchar_one input_keys('か') - assert_line('か') - assert_byte_pointer_size('か') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('か', '') end def test_ed_insert_mbchar_two input_keys('かき') - assert_line('かき') - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('かき', '') end def test_ed_insert_for_mbchar_by_plural_code_points input_keys("か\u3099") - assert_line("か\u3099") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor("か\u3099", '') end def test_ed_insert_for_plural_mbchar_by_plural_code_points input_keys("か\u3099き\u3099") - assert_line("か\u3099き\u3099") - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor("か\u3099き\u3099", '') end def test_ed_next_char input_keys("abcdef\C-[0") - assert_line('abcdef') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'abcdef') input_keys('l') - assert_line('abcdef') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(6) + assert_line_around_cursor('a', 'bcdef') input_keys('2l') - assert_line('abcdef') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(6) + assert_line_around_cursor('abc', 'def') end def test_ed_prev_char input_keys("abcdef\C-[") - assert_line('abcdef') - assert_byte_pointer_size('abcde') - assert_cursor(5) - assert_cursor_max(6) + assert_line_around_cursor('abcde', 'f') input_keys('h') - assert_line('abcdef') - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor('abcd', 'ef') input_keys('2h') - assert_line('abcdef') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor('ab', 'cdef') end def test_history Reline::HISTORY.concat(%w{abc 123 AAA}) input_keys("\C-[") - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys('k') - assert_line('AAA') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'AAA') input_keys('2k') - assert_line('abc') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'abc') input_keys('j') - assert_line('123') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', '123') input_keys('2j') - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') end def test_vi_paste_prev input_keys("abcde\C-[3h") - assert_line('abcde') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(5) + assert_line_around_cursor('a', 'bcde') input_keys('P') - assert_line('abcde') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(5) + assert_line_around_cursor('a', 'bcde') input_keys('d$') - assert_line('a') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) + assert_line_around_cursor('', 'a') input_keys('P') - assert_line('bcdea') - assert_byte_pointer_size('bcd') - assert_cursor(3) - assert_cursor_max(5) + assert_line_around_cursor('bcd', 'ea') input_keys('2P') - assert_line('bcdbcdbcdeeea') - assert_byte_pointer_size('bcdbcdbcd') - assert_cursor(9) - assert_cursor_max(13) + assert_line_around_cursor('bcdbcdbcd', 'eeea') end def test_vi_paste_next input_keys("abcde\C-[3h") - assert_line('abcde') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(5) + assert_line_around_cursor('a', 'bcde') input_keys('p') - assert_line('abcde') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(5) + assert_line_around_cursor('a', 'bcde') input_keys('d$') - assert_line('a') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) + assert_line_around_cursor('', 'a') input_keys('p') - assert_line('abcde') - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(5) + assert_line_around_cursor('abcd', 'e') input_keys('2p') - assert_line('abcdebcdebcde') - assert_byte_pointer_size('abcdebcdebcd') - assert_cursor(12) - assert_cursor_max(13) + assert_line_around_cursor('abcdebcdebcd', 'e') end def test_vi_paste_prev_for_mbchar input_keys("あいうえお\C-[3h") - assert_line('あいうえお') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor('あ', 'いうえお') input_keys('P') - assert_line('あいうえお') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor('あ', 'いうえお') input_keys('d$') - assert_line('あ') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) + assert_line_around_cursor('', 'あ') input_keys('P') - assert_line('いうえおあ') - assert_byte_pointer_size('いうえ') - assert_cursor(6) - assert_cursor_max(10) + assert_line_around_cursor('いうえ', 'おあ') input_keys('2P') - assert_line('いうえいうえいうえおおおあ') - assert_byte_pointer_size('いうえいうえいうえ') - assert_cursor(18) - assert_cursor_max(26) + assert_line_around_cursor('いうえいうえいうえ', 'おおおあ') end def test_vi_paste_next_for_mbchar input_keys("あいうえお\C-[3h") - assert_line('あいうえお') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor('あ', 'いうえお') input_keys('p') - assert_line('あいうえお') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor('あ', 'いうえお') input_keys('d$') - assert_line('あ') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) + assert_line_around_cursor('', 'あ') input_keys('p') - assert_line('あいうえお') - assert_byte_pointer_size('あいうえ') - assert_cursor(8) - assert_cursor_max(10) + assert_line_around_cursor('あいうえ', 'お') input_keys('2p') - assert_line('あいうえおいうえおいうえお') - assert_byte_pointer_size('あいうえおいうえおいうえ') - assert_cursor(24) - assert_cursor_max(26) + assert_line_around_cursor('あいうえおいうえおいうえ', 'お') end def test_vi_paste_prev_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099く\u3099け\u3099こ\u3099\C-[3h") - assert_line("か\u3099き\u3099く\u3099け\u3099こ\u3099") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099") input_keys('P') - assert_line("か\u3099き\u3099く\u3099け\u3099こ\u3099") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099") input_keys('d$') - assert_line("か\u3099") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) + assert_line_around_cursor('', "か\u3099") input_keys('P') - assert_line("き\u3099く\u3099け\u3099こ\u3099か\u3099") - assert_byte_pointer_size("き\u3099く\u3099け\u3099") - assert_cursor(6) - assert_cursor_max(10) + assert_line_around_cursor("き\u3099く\u3099け\u3099", "こ\u3099か\u3099") input_keys('2P') - assert_line("き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099こ\u3099こ\u3099こ\u3099か\u3099") - assert_byte_pointer_size("き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099") - assert_cursor(18) - assert_cursor_max(26) + assert_line_around_cursor("き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099", "こ\u3099こ\u3099こ\u3099か\u3099") end def test_vi_paste_next_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099く\u3099け\u3099こ\u3099\C-[3h") - assert_line("か\u3099き\u3099く\u3099け\u3099こ\u3099") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099") input_keys('p') - assert_line("か\u3099き\u3099く\u3099け\u3099こ\u3099") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099") input_keys('d$') - assert_line("か\u3099") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) + assert_line_around_cursor('', "か\u3099") input_keys('p') - assert_line("か\u3099き\u3099く\u3099け\u3099こ\u3099") - assert_byte_pointer_size("か\u3099き\u3099く\u3099け\u3099") - assert_cursor(8) - assert_cursor_max(10) + assert_line_around_cursor("か\u3099き\u3099く\u3099け\u3099", "こ\u3099") input_keys('2p') - assert_line("か\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099こ\u3099") - assert_byte_pointer_size("か\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099") - assert_cursor(24) - assert_cursor_max(26) + assert_line_around_cursor("か\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099", "こ\u3099") end def test_vi_prev_next_word input_keys("aaa b{b}b ccc\C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}b ccc') input_keys('w') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(13) + assert_line_around_cursor('aaa ', 'b{b}b ccc') input_keys('w') - assert_byte_pointer_size('aaa b') - assert_cursor(5) - assert_cursor_max(13) + assert_line_around_cursor('aaa b', '{b}b ccc') input_keys('w') - assert_byte_pointer_size('aaa b{') - assert_cursor(6) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{', 'b}b ccc') input_keys('w') - assert_byte_pointer_size('aaa b{b') - assert_cursor(7) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b', '}b ccc') input_keys('w') - assert_byte_pointer_size('aaa b{b}') - assert_cursor(8) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}', 'b ccc') input_keys('w') - assert_byte_pointer_size('aaa b{b}b ') - assert_cursor(10) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b ', 'ccc') input_keys('w') - assert_byte_pointer_size('aaa b{b}b cc') - assert_cursor(12) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b cc', 'c') input_keys('b') - assert_byte_pointer_size('aaa b{b}b ') - assert_cursor(10) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b ', 'ccc') input_keys('b') - assert_byte_pointer_size('aaa b{b}') - assert_cursor(8) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}', 'b ccc') input_keys('b') - assert_byte_pointer_size('aaa b{b') - assert_cursor(7) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b', '}b ccc') input_keys('b') - assert_byte_pointer_size('aaa b{') - assert_cursor(6) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{', 'b}b ccc') input_keys('b') - assert_byte_pointer_size('aaa b') - assert_cursor(5) - assert_cursor_max(13) + assert_line_around_cursor('aaa b', '{b}b ccc') input_keys('b') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(13) + assert_line_around_cursor('aaa ', 'b{b}b ccc') input_keys('b') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}b ccc') input_keys('3w') - assert_byte_pointer_size('aaa b{') - assert_cursor(6) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{', 'b}b ccc') input_keys('3w') - assert_byte_pointer_size('aaa b{b}b ') - assert_cursor(10) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b ', 'ccc') input_keys('3w') - assert_byte_pointer_size('aaa b{b}b cc') - assert_cursor(12) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b cc', 'c') input_keys('3b') - assert_byte_pointer_size('aaa b{b') - assert_cursor(7) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b', '}b ccc') input_keys('3b') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(13) + assert_line_around_cursor('aaa ', 'b{b}b ccc') input_keys('3b') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}b ccc') end def test_vi_end_word input_keys("aaa b{b}}}b ccc\C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(19) + assert_line_around_cursor('', 'aaa b{b}}}b ccc') input_keys('e') - assert_byte_pointer_size('aa') - assert_cursor(2) - assert_cursor_max(19) + assert_line_around_cursor('aa', 'a b{b}}}b ccc') input_keys('e') - assert_byte_pointer_size('aaa ') - assert_cursor(6) - assert_cursor_max(19) + assert_line_around_cursor('aaa ', 'b{b}}}b ccc') input_keys('e') - assert_byte_pointer_size('aaa b') - assert_cursor(7) - assert_cursor_max(19) + assert_line_around_cursor('aaa b', '{b}}}b ccc') input_keys('e') - assert_byte_pointer_size('aaa b{') - assert_cursor(8) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{', 'b}}}b ccc') input_keys('e') - assert_byte_pointer_size('aaa b{b}}') - assert_cursor(11) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}', '}b ccc') input_keys('e') - assert_byte_pointer_size('aaa b{b}}}') - assert_cursor(12) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}', 'b ccc') input_keys('e') - assert_byte_pointer_size('aaa b{b}}}b cc') - assert_cursor(18) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}b cc', 'c') input_keys('e') - assert_byte_pointer_size('aaa b{b}}}b cc') - assert_cursor(18) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}b cc', 'c') input_keys('03e') - assert_byte_pointer_size('aaa b') - assert_cursor(7) - assert_cursor_max(19) + assert_line_around_cursor('aaa b', '{b}}}b ccc') input_keys('3e') - assert_byte_pointer_size('aaa b{b}}}') - assert_cursor(12) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}', 'b ccc') input_keys('3e') - assert_byte_pointer_size('aaa b{b}}}b cc') - assert_cursor(18) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}b cc', 'c') end def test_vi_prev_next_big_word input_keys("aaa b{b}b ccc\C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}b ccc') input_keys('W') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(13) + assert_line_around_cursor('aaa ', 'b{b}b ccc') input_keys('W') - assert_byte_pointer_size('aaa b{b}b ') - assert_cursor(10) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b ', 'ccc') input_keys('W') - assert_byte_pointer_size('aaa b{b}b cc') - assert_cursor(12) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b cc', 'c') input_keys('B') - assert_byte_pointer_size('aaa b{b}b ') - assert_cursor(10) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b ', 'ccc') input_keys('B') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(13) + assert_line_around_cursor('aaa ', 'b{b}b ccc') input_keys('B') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}b ccc') input_keys('2W') - assert_byte_pointer_size('aaa b{b}b ') - assert_cursor(10) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b ', 'ccc') input_keys('2W') - assert_byte_pointer_size('aaa b{b}b cc') - assert_cursor(12) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b cc', 'c') input_keys('2B') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(13) + assert_line_around_cursor('aaa ', 'b{b}b ccc') input_keys('2B') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}b ccc') end def test_vi_end_big_word input_keys("aaa b{b}}}b ccc\C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(19) + assert_line_around_cursor('', 'aaa b{b}}}b ccc') input_keys('E') - assert_byte_pointer_size('aa') - assert_cursor(2) - assert_cursor_max(19) + assert_line_around_cursor('aa', 'a b{b}}}b ccc') input_keys('E') - assert_byte_pointer_size('aaa b{b}}}') - assert_cursor(12) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}', 'b ccc') input_keys('E') - assert_byte_pointer_size('aaa b{b}}}b cc') - assert_cursor(18) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}b cc', 'c') input_keys('E') - assert_byte_pointer_size('aaa b{b}}}b cc') - assert_cursor(18) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}b cc', 'c') end def test_ed_quoted_insert input_keys("ab\C-v\C-acd") - assert_line("ab\C-acd") - assert_byte_pointer_size("ab\C-acd") - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor("ab\C-acd", '') end def test_ed_quoted_insert_with_vi_arg input_keys("ab\C-[3\C-v\C-aacd") - assert_line("a\C-a\C-a\C-abcd") - assert_byte_pointer_size("a\C-a\C-a\C-abcd") - assert_cursor(10) - assert_cursor_max(10) + assert_line_around_cursor("a\C-a\C-a\C-abcd", '') end def test_vi_replace_char input_keys("abcdef\C-[03l") - assert_line('abcdef') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(6) + assert_line_around_cursor('abc', 'def') input_keys('rz') - assert_line('abczef') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(6) + assert_line_around_cursor('abc', 'zef') input_keys('2rx') - assert_line('abcxxf') - assert_byte_pointer_size('abcxx') - assert_cursor(5) - assert_cursor_max(6) + assert_line_around_cursor('abcxx', 'f') end def test_vi_replace_char_with_mbchar input_keys("あいうえお\C-[0l") - assert_line('あいうえお') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor('あ', 'いうえお') input_keys('rx') - assert_line('あxうえお') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(9) + assert_line_around_cursor('あ', 'xうえお') input_keys('l2ry') - assert_line('あxyyお') - assert_byte_pointer_size('あxyy') - assert_cursor(5) - assert_cursor_max(7) + assert_line_around_cursor('あxyy', 'お') end def test_vi_next_char input_keys("abcdef\C-[0") - assert_line('abcdef') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'abcdef') input_keys('fz') - assert_line('abcdef') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'abcdef') input_keys('fe') - assert_line('abcdef') - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor('abcd', 'ef') end def test_vi_to_next_char input_keys("abcdef\C-[0") - assert_line('abcdef') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'abcdef') input_keys('tz') - assert_line('abcdef') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'abcdef') input_keys('te') - assert_line('abcdef') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(6) + assert_line_around_cursor('abc', 'def') end def test_vi_prev_char input_keys("abcdef\C-[") - assert_line('abcdef') - assert_byte_pointer_size('abcde') - assert_cursor(5) - assert_cursor_max(6) + assert_line_around_cursor('abcde', 'f') input_keys('Fz') - assert_line('abcdef') - assert_byte_pointer_size('abcde') - assert_cursor(5) - assert_cursor_max(6) + assert_line_around_cursor('abcde', 'f') input_keys('Fa') - assert_line('abcdef') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'abcdef') end def test_vi_to_prev_char input_keys("abcdef\C-[") - assert_line('abcdef') - assert_byte_pointer_size('abcde') - assert_cursor(5) - assert_cursor_max(6) + assert_line_around_cursor('abcde', 'f') input_keys('Tz') - assert_line('abcdef') - assert_byte_pointer_size('abcde') - assert_cursor(5) - assert_cursor_max(6) + assert_line_around_cursor('abcde', 'f') input_keys('Ta') - assert_line('abcdef') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(6) + assert_line_around_cursor('a', 'bcdef') end def test_vi_delete_next_char input_keys("abc\C-[h") - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('a', 'bc') input_keys('x') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(2) - assert_line('ac') + assert_line_around_cursor('a', 'c') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) - assert_line('a') + assert_line_around_cursor('', 'a') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_vi_delete_next_char_for_mbchar input_keys("あいう\C-[h") - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(6) - assert_line('あいう') + assert_line_around_cursor('あ', 'いう') input_keys('x') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(4) - assert_line('あう') + assert_line_around_cursor('あ', 'う') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) - assert_line('あ') + assert_line_around_cursor('', 'あ') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_vi_delete_next_char_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099く\u3099\C-[h") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(6) - assert_line("か\u3099き\u3099く\u3099") + assert_line_around_cursor("か\u3099", "き\u3099く\u3099") input_keys('x') - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(4) - assert_line("か\u3099く\u3099") + assert_line_around_cursor("か\u3099", "く\u3099") input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) - assert_line("か\u3099") + assert_line_around_cursor('', "か\u3099") input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_vi_delete_prev_char input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') input_keys("\C-h") - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(1) - assert_line('a') + assert_line_around_cursor('a', '') end def test_vi_delete_prev_char_for_mbchar input_keys('かき') - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('かき', '') input_keys("\C-h") - assert_byte_pointer_size('か') - assert_cursor(2) - assert_cursor_max(2) - assert_line('か') + assert_line_around_cursor('か', '') end def test_vi_delete_prev_char_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099") - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor("か\u3099き\u3099", '') input_keys("\C-h") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(2) - assert_line("か\u3099") + assert_line_around_cursor("か\u3099", '') end def test_ed_delete_prev_char input_keys("abcdefg\C-[h") - assert_byte_pointer_size('abcde') - assert_cursor(5) - assert_cursor_max(7) - assert_line('abcdefg') + assert_line_around_cursor('abcde', 'fg') input_keys('X') - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(6) - assert_line('abcdfg') + assert_line_around_cursor('abcd', 'fg') input_keys('3X') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) - assert_line('afg') + assert_line_around_cursor('a', 'fg') input_keys('p') - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(6) - assert_line('afbcdg') + assert_line_around_cursor('afbc', 'dg') end def test_ed_delete_prev_word input_keys('abc def{bbb}ccc') - assert_byte_pointer_size('abc def{bbb}ccc') - assert_cursor(15) - assert_cursor_max(15) + assert_line_around_cursor('abc def{bbb}ccc', '') input_keys("\C-w") - assert_byte_pointer_size('abc def{bbb}') - assert_cursor(12) - assert_cursor_max(12) - assert_line('abc def{bbb}') + assert_line_around_cursor('abc def{bbb}', '') input_keys("\C-w") - assert_byte_pointer_size('abc def{') - assert_cursor(8) - assert_cursor_max(8) - assert_line('abc def{') + assert_line_around_cursor('abc def{', '') input_keys("\C-w") - assert_byte_pointer_size('abc ') - assert_cursor(4) - assert_cursor_max(4) - assert_line('abc ') + assert_line_around_cursor('abc ', '') input_keys("\C-w") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_delete_prev_word_for_mbchar input_keys('あいう かきく{さしす}たちつ') - assert_byte_pointer_size('あいう かきく{さしす}たちつ') - assert_cursor(27) - assert_cursor_max(27) + assert_line_around_cursor('あいう かきく{さしす}たちつ', '') input_keys("\C-w") - assert_byte_pointer_size('あいう かきく{さしす}') - assert_cursor(21) - assert_cursor_max(21) - assert_line('あいう かきく{さしす}') + assert_line_around_cursor('あいう かきく{さしす}', '') input_keys("\C-w") - assert_byte_pointer_size('あいう かきく{') - assert_cursor(14) - assert_cursor_max(14) - assert_line('あいう かきく{') + assert_line_around_cursor('あいう かきく{', '') input_keys("\C-w") - assert_byte_pointer_size('あいう ') - assert_cursor(7) - assert_cursor_max(7) - assert_line('あいう ') + assert_line_around_cursor('あいう ', '') input_keys("\C-w") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_delete_prev_word_for_mbchar_by_plural_code_points input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_cursor(27) - assert_cursor_max(27) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", '') input_keys("\C-w") - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}") - assert_cursor(21) - assert_cursor_max(21) - assert_line("あいう か\u3099き\u3099く\u3099{さしす}") + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}", '') input_keys("\C-w") - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{") - assert_cursor(14) - assert_cursor_max(14) - assert_line("あいう か\u3099き\u3099く\u3099{") + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{", '') input_keys("\C-w") - assert_byte_pointer_size('あいう ') - assert_cursor(7) - assert_cursor_max(7) - assert_line('あいう ') + assert_line_around_cursor('あいう ', '') input_keys("\C-w") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_newline_with_cr input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') refute(@line_editor.finished?) input_keys("\C-m") - assert_line('ab') + assert_line_around_cursor('ab', '') assert(@line_editor.finished?) end def test_ed_newline_with_lf input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') refute(@line_editor.finished?) input_keys("\C-j") - assert_line('ab') + assert_line_around_cursor('ab', '') assert(@line_editor.finished?) end def test_vi_list_or_eof input_keys("\C-d") # quit from inputing - assert_line(nil) + assert_nil(@line_editor.line) assert(@line_editor.finished?) end def test_vi_list_or_eof_with_non_empty_line input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') refute(@line_editor.finished?) input_keys("\C-d") - assert_line('ab') + assert_line_around_cursor('ab', '') assert(@line_editor.finished?) end @@ -982,40 +545,19 @@ def test_completion_journey } } input_keys('foo') - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') input_keys("\C-n") - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') input_keys("\C-n") - assert_byte_pointer_size('foo_bar_baz') - assert_cursor(11) - assert_cursor_max(11) - assert_line('foo_bar_baz') + assert_line_around_cursor('foo_bar_baz', '') input_keys("\C-n") - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') input_keys("\C-n") - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') input_keys("_\C-n") - assert_byte_pointer_size('foo_bar_baz') - assert_cursor(11) - assert_cursor_max(11) - assert_line('foo_bar_baz') + assert_line_around_cursor('foo_bar_baz', '') input_keys("\C-n") - assert_byte_pointer_size('foo_bar_') - assert_cursor(8) - assert_cursor_max(8) - assert_line('foo_bar_') + assert_line_around_cursor('foo_bar_', '') end def test_completion_journey_reverse @@ -1028,40 +570,19 @@ def test_completion_journey_reverse } } input_keys('foo') - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') input_keys("\C-p") - assert_byte_pointer_size('foo_bar_baz') - assert_cursor(11) - assert_cursor_max(11) - assert_line('foo_bar_baz') + assert_line_around_cursor('foo_bar_baz', '') input_keys("\C-p") - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') input_keys("\C-p") - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') input_keys("\C-p") - assert_byte_pointer_size('foo_bar_baz') - assert_cursor(11) - assert_cursor_max(11) - assert_line('foo_bar_baz') + assert_line_around_cursor('foo_bar_baz', '') input_keys("\C-h\C-p") - assert_byte_pointer_size('foo_bar_baz') - assert_cursor(11) - assert_cursor_max(11) - assert_line('foo_bar_baz') + assert_line_around_cursor('foo_bar_baz', '') input_keys("\C-p") - assert_byte_pointer_size('foo_bar_ba') - assert_cursor(10) - assert_cursor_max(10) - assert_line('foo_bar_ba') + assert_line_around_cursor('foo_bar_ba', '') end def test_completion_journey_in_middle_of_line @@ -1074,42 +595,21 @@ def test_completion_journey_in_middle_of_line } } input_keys('abcde fo ABCDE') - assert_line('abcde fo ABCDE') + assert_line_around_cursor('abcde fo ABCDE', '') input_keys("\C-[" + 'h' * 5 + "i\C-n") - assert_byte_pointer_size('abcde foo_bar') - assert_cursor(13) - assert_cursor_max(19) - assert_line('abcde foo_bar ABCDE') + assert_line_around_cursor('abcde foo_bar', ' ABCDE') input_keys("\C-n") - assert_byte_pointer_size('abcde foo_bar_baz') - assert_cursor(17) - assert_cursor_max(23) - assert_line('abcde foo_bar_baz ABCDE') + assert_line_around_cursor('abcde foo_bar_baz', ' ABCDE') input_keys("\C-n") - assert_byte_pointer_size('abcde fo') - assert_cursor(8) - assert_cursor_max(14) - assert_line('abcde fo ABCDE') + assert_line_around_cursor('abcde fo', ' ABCDE') input_keys("\C-n") - assert_byte_pointer_size('abcde foo_bar') - assert_cursor(13) - assert_cursor_max(19) - assert_line('abcde foo_bar ABCDE') + assert_line_around_cursor('abcde foo_bar', ' ABCDE') input_keys("_\C-n") - assert_byte_pointer_size('abcde foo_bar_baz') - assert_cursor(17) - assert_cursor_max(23) - assert_line('abcde foo_bar_baz ABCDE') + assert_line_around_cursor('abcde foo_bar_baz', ' ABCDE') input_keys("\C-n") - assert_byte_pointer_size('abcde foo_bar_') - assert_cursor(14) - assert_cursor_max(20) - assert_line('abcde foo_bar_ ABCDE') + assert_line_around_cursor('abcde foo_bar_', ' ABCDE') input_keys("\C-n") - assert_byte_pointer_size('abcde foo_bar_baz') - assert_cursor(17) - assert_cursor_max(23) - assert_line('abcde foo_bar_baz ABCDE') + assert_line_around_cursor('abcde foo_bar_baz', ' ABCDE') end def test_completion @@ -1122,15 +622,9 @@ def test_completion } } input_keys('foo') - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') input_keys("\C-i") - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') end def test_completion_with_disable_completion @@ -1144,324 +638,160 @@ def test_completion_with_disable_completion } } input_keys('foo') - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') input_keys("\C-i") - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') end def test_vi_first_print input_keys("abcde\C-[^") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) + assert_line_around_cursor('', 'abcde') input_keys("0\C-ki") input_keys(" abcde\C-[^") - assert_byte_pointer_size(' ') - assert_cursor(1) - assert_cursor_max(6) + assert_line_around_cursor(' ', 'abcde') input_keys("0\C-ki") input_keys(" abcde ABCDE \C-[^") - assert_byte_pointer_size(' ') - assert_cursor(3) - assert_cursor_max(17) + assert_line_around_cursor(' ', 'abcde ABCDE ') end def test_ed_move_to_beg input_keys("abcde\C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) + assert_line_around_cursor('', 'abcde') input_keys("0\C-ki") input_keys(" abcde\C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', ' abcde') input_keys("0\C-ki") input_keys(" abcde ABCDE \C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(17) + assert_line_around_cursor('', ' abcde ABCDE ') end def test_vi_delete_meta input_keys("aaa bbb ccc ddd eee\C-[02w") - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(19) - assert_line('aaa bbb ccc ddd eee') + assert_line_around_cursor('aaa bbb ', 'ccc ddd eee') input_keys('dw') - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(15) - assert_line('aaa bbb ddd eee') + assert_line_around_cursor('aaa bbb ', 'ddd eee') input_keys('db') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(11) - assert_line('aaa ddd eee') + assert_line_around_cursor('aaa ', 'ddd eee') end def test_vi_delete_meta_with_vi_next_word_at_eol input_keys("foo bar\C-[0w") - assert_byte_pointer_size('foo ') - assert_cursor(4) - assert_cursor_max(7) - assert_line('foo bar') + assert_line_around_cursor('foo ', 'bar') input_keys('w') - assert_byte_pointer_size('foo ba') - assert_cursor(6) - assert_cursor_max(7) - assert_line('foo bar') + assert_line_around_cursor('foo ba', 'r') input_keys('0dw') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) - assert_line('bar') + assert_line_around_cursor('', 'bar') input_keys('dw') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_vi_delete_meta_with_vi_next_char input_keys("aaa bbb ccc ___ ddd\C-[02w") - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(19) - assert_line('aaa bbb ccc ___ ddd') + assert_line_around_cursor('aaa bbb ', 'ccc ___ ddd') input_keys('df_') - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(14) - assert_line('aaa bbb __ ddd') + assert_line_around_cursor('aaa bbb ', '__ ddd') end def test_vi_delete_meta_with_arg input_keys("aaa bbb ccc\C-[02w") - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(11) - assert_line('aaa bbb ccc') + assert_line_around_cursor('aaa bbb ', 'ccc') input_keys('2dl') - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(9) - assert_line('aaa bbb c') + assert_line_around_cursor('aaa bbb ', 'c') end def test_vi_change_meta input_keys("aaa bbb ccc ddd eee\C-[02w") - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(19) - assert_line('aaa bbb ccc ddd eee') + assert_line_around_cursor('aaa bbb ', 'ccc ddd eee') input_keys('cwaiueo') - assert_byte_pointer_size('aaa bbb aiueo') - assert_cursor(13) - assert_cursor_max(21) - assert_line('aaa bbb aiueo ddd eee') + assert_line_around_cursor('aaa bbb aiueo', ' ddd eee') input_keys("\C-[") - assert_byte_pointer_size('aaa bbb aiue') - assert_cursor(12) - assert_cursor_max(21) - assert_line('aaa bbb aiueo ddd eee') + assert_line_around_cursor('aaa bbb aiue', 'o ddd eee') input_keys('cb') - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(17) - assert_line('aaa bbb o ddd eee') + assert_line_around_cursor('aaa bbb ', 'o ddd eee') end def test_vi_change_meta_with_vi_next_word input_keys("foo bar baz\C-[0w") - assert_byte_pointer_size('foo ') - assert_cursor(5) - assert_cursor_max(13) - assert_line('foo bar baz') + assert_line_around_cursor('foo ', 'bar baz') input_keys('cwhoge') - assert_byte_pointer_size('foo hoge') - assert_cursor(9) - assert_cursor_max(14) - assert_line('foo hoge baz') + assert_line_around_cursor('foo hoge', ' baz') input_keys("\C-[") - assert_byte_pointer_size('foo hog') - assert_cursor(8) - assert_cursor_max(14) - assert_line('foo hoge baz') + assert_line_around_cursor('foo hog', 'e baz') end def test_unimplemented_vi_command_should_be_no_op input_keys("abc\C-[h") - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('a', 'bc') input_keys('@') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('a', 'bc') end def test_vi_yank input_keys("foo bar\C-[0") - assert_line('foo bar') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) + assert_line_around_cursor('', 'foo bar') input_keys('y3l') - assert_line('foo bar') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) + assert_line_around_cursor('', 'foo bar') input_keys('P') - assert_line('foofoo bar') - assert_byte_pointer_size('fo') - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor('fo', 'ofoo bar') end def test_vi_end_word_with_operator input_keys("foo bar\C-[0") - assert_line('foo bar') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) + assert_line_around_cursor('', 'foo bar') input_keys('de') - assert_line(' bar') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) + assert_line_around_cursor('', ' bar') input_keys('de') - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys('de') - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') end def test_vi_end_big_word_with_operator input_keys("aaa b{b}}}b\C-[0") - assert_line('aaa b{b}}}b') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}}}b') input_keys('dE') - assert_line(' b{b}}}b') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(10) + assert_line_around_cursor('', ' b{b}}}b') input_keys('dE') - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys('dE') - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') end def test_vi_next_char_with_operator input_keys("foo bar\C-[0") - assert_line('foo bar') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) + assert_line_around_cursor('', 'foo bar') input_keys('df ') - assert_line('bar') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) - end - - def test_pasting - start_pasting - input_keys('ab') - finish_pasting - input_keys('c') - assert_line('abc') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) - end - - def test_pasting_fullwidth - start_pasting - input_keys('あ') - finish_pasting - input_keys('い') - assert_line('あい') - assert_byte_pointer_size('あい') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('', 'bar') end def test_ed_delete_next_char_at_eol input_keys('"あ"') - assert_line('"あ"') - assert_byte_pointer_size('"あ"') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('"あ"', '') input_keys("\C-[") - assert_line('"あ"') - assert_byte_pointer_size('"あ') - assert_cursor(3) - assert_cursor_max(4) + assert_line_around_cursor('"あ', '"') input_keys('xa"') - assert_line('"あ"') - assert_byte_pointer_size('"あ"') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('"あ"', '') end def test_vi_kill_line_prev input_keys("\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') input_keys("\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') input_keys("\C-[\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) - assert_line('c') + assert_line_around_cursor('', 'c') input_keys("\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) - assert_line('c') + assert_line_around_cursor('', 'c') end def test_vi_change_to_eol input_keys("abcdef\C-[2hC") - assert_line("abc") + assert_line_around_cursor('abc', '') input_keys("\C-[0C") - assert_line("") - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) end diff --git a/test/reline/test_line_editor.rb b/test/reline/test_line_editor.rb index c552787dc7e092..0963d2c8fe835c 100644 --- a/test/reline/test_line_editor.rb +++ b/test/reline/test_line_editor.rb @@ -4,6 +4,18 @@ class Reline::LineEditor class RenderLineDifferentialTest < Reline::TestCase + module TestIO + RESET_COLOR = "\e[0m" + + def self.move_cursor_column(col) + @output << "[COL_#{col}]" + end + + def self.erase_after_cursor + @output << '[ERASE]' + end + end + def setup verbose, $VERBOSE = $VERBOSE, nil @line_editor = Reline::LineEditor.new(nil, Encoding::UTF_8) @@ -12,14 +24,8 @@ def setup @line_editor.instance_variable_set(:@screen_size, [24, 80]) @line_editor.instance_variable_set(:@output, @output) Reline.send(:remove_const, :IOGate) - Reline.const_set(:IOGate, Object.new) + Reline.const_set(:IOGate, TestIO) Reline::IOGate.instance_variable_set(:@output, @output) - def (Reline::IOGate).move_cursor_column(col) - @output << "[COL_#{col}]" - end - def (Reline::IOGate).erase_after_cursor - @output << '[ERASE]' - end ensure $VERBOSE = verbose end diff --git a/test/reline/yamatanooroti/multiline_repl b/test/reline/yamatanooroti/multiline_repl index 5205e1f5d95a5a..66bcf51e1add72 100755 --- a/test/reline/yamatanooroti/multiline_repl +++ b/test/reline/yamatanooroti/multiline_repl @@ -183,7 +183,7 @@ opt.on('--autocomplete-long') { opt.on('--autocomplete-super-long') { Reline.autocompletion = true Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| - c = 'A' + c = +'A' 2000.times.map{ s = "Str_#{c}"; c.succ!; s }.select{ |c| c.start_with?(target) } } } diff --git a/test/reline/yamatanooroti/test_rendering.rb b/test/reline/yamatanooroti/test_rendering.rb index 527da519c1c78c..efb1e01562b905 100644 --- a/test/reline/yamatanooroti/test_rendering.rb +++ b/test/reline/yamatanooroti/test_rendering.rb @@ -197,9 +197,12 @@ def test_mode_string_vi LINES start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') write(":a\n\C-[k") + write("i\n:a") + write("\C-[h") close assert_screen(<<~EOC) - Multiline REPL. + (ins)prompt> :a + => :a (ins)prompt> :a => :a (cmd)prompt> :a diff --git a/test/ruby/test_backtrace.rb b/test/ruby/test_backtrace.rb index 60f9605e40fe7f..cfc65faacb1ab1 100644 --- a/test/ruby/test_backtrace.rb +++ b/test/ruby/test_backtrace.rb @@ -397,7 +397,6 @@ def foo end; err = ["-:7:in 'Object#bar': bar! (RuntimeError)", - "\tfrom -:4:in 'Object#bar'", "\tfrom -:9:in '
'", "-:2:in 'Object#foo': foo! (RuntimeError)", "\tfrom -:5:in 'Object#bar'", diff --git a/test/ruby/test_default_gems.rb b/test/ruby/test_default_gems.rb index b9de33cc78d5b8..b82e304cbdb1c6 100644 --- a/test/ruby/test_default_gems.rb +++ b/test/ruby/test_default_gems.rb @@ -9,7 +9,7 @@ def self.load(file) # - `git ls-files` is useless under ruby's repository # - `2>/dev/null` works only on Unix-like platforms code.gsub!(/(?:`git[^\`]*`|%x\[git[^\]]*\])\.split\([^\)]*\)/m, '[]') - code.gsub!(/IO\.popen\(.*git.*?\)/, '[].each') + code.gsub!(/IO\.popen\(.*git.*?\)/, '[] || itself') eval(code, binding, file) end diff --git a/test/ruby/test_fiber.rb b/test/ruby/test_fiber.rb index 1fb6103d8a18ba..45e5d12092d5db 100644 --- a/test/ruby/test_fiber.rb +++ b/test/ruby/test_fiber.rb @@ -424,7 +424,7 @@ def test_exit_in_fiber end def test_fatal_in_fiber - assert_in_out_err(["-r-test-/fatal/rb_fatal", "-e", <<-EOS], "", [], /ok/) + assert_in_out_err(["-r-test-/fatal", "-e", <<-EOS], "", [], /ok/) Fiber.new{ Bug.rb_fatal "ok" }.resume diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index 5d0262a4498b0e..34a80c37293eb8 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -2835,6 +2835,19 @@ def bar(*a, **kw) assert_equal({a: 1}, kw) end + def test_anon_splat_ruby2_keywords_bug_20388 + extend(Module.new{def process(action, ...) 1 end}) + extend(Module.new do + def process(action, *args) + args.freeze + super + end + ruby2_keywords :process + end) + + assert_equal(1, process(:foo, bar: :baz)) + end + def test_top_ruby2_keywords assert_in_out_err([], <<-INPUT, ["[1, 2, 3]", "{:k=>1}"], []) def bar(*a, **kw) diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb index a4ca08ec277c92..62498170fd5242 100644 --- a/test/ruby/test_parse.rb +++ b/test/ruby/test_parse.rb @@ -1526,6 +1526,24 @@ def test_shareable_constant_value_simple assert_not_ractor_shareable(obj) assert_equal obj, a assert !obj.equal?(a) + + bug_20339 = '[ruby-core:117186] [Bug #20339]' + bug_20341 = '[ruby-core:117197] [Bug #20341]' + a, b = eval_separately(<<~'end;') + # shareable_constant_value: literal + foo = 1 + bar = 2 + A = { foo => bar } + B = [foo, bar] + [A, B] + end; + + assert_ractor_shareable(a) + assert_ractor_shareable(b) + assert_equal([1], a.keys, bug_20339) + assert_equal([2], a.values, bug_20339) + assert_equal(1, b[0], bug_20341) + assert_equal(2, b[1], bug_20341) end def test_shareable_constant_value_nested diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index 3f1b91a6a93809..8ec80d06fc7f2f 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -3629,6 +3629,9 @@ def test_chilled_string end def test_chilled_string_setivar + deprecated = Warning[:deprecated] + Warning[:deprecated] = false + String.class_eval <<~RUBY, __FILE__, __LINE__ + 1 def setivar! @ivar = 42 @@ -3641,6 +3644,20 @@ def setivar! ensure String.undef_method(:setivar!) end + ensure + Warning[:deprecated] = deprecated + end + + def test_chilled_string_substring + deprecated = Warning[:deprecated] + Warning[:deprecated] = false + chilled_string = eval('"a chilled string."') + substring = chilled_string[0..-1] + assert_equal("a chilled string.", substring) + chilled_string[0..-1] = "This string is defrosted." + assert_equal("a chilled string.", substring) + ensure + Warning[:deprecated] = deprecated end private diff --git a/test/ruby/test_vm_dump.rb b/test/ruby/test_vm_dump.rb index 9c06ec14fb2736..c718f69316409b 100644 --- a/test/ruby/test_vm_dump.rb +++ b/test/ruby/test_vm_dump.rb @@ -1,14 +1,15 @@ # frozen_string_literal: true require 'test/unit' +return unless /darwin/ =~ RUBY_PLATFORM + class TestVMDump < Test::Unit::TestCase def assert_darwin_vm_dump_works(args) - omit if RUBY_PLATFORM !~ /darwin/ assert_in_out_err(args, "", [], /^\[IMPORTANT\]/) end def test_darwin_invalid_call - assert_darwin_vm_dump_works(['-rfiddle', '-eFiddle::Function.new(Fiddle::Pointer.new(1), [], Fiddle::TYPE_VOID).call']) + assert_darwin_vm_dump_works(['-r-test-/fatal', '-eBug.invalid_call(1)']) end def test_darwin_segv_in_syscall @@ -16,6 +17,6 @@ def test_darwin_segv_in_syscall end def test_darwin_invalid_access - assert_darwin_vm_dump_works(['-rfiddle', '-eFiddle.dlunwrap(100).inspect']) + assert_darwin_vm_dump_works(['-r-test-/fatal', '-eBug.invalid_access(100)']) end end diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index d4c307978e7c5d..244b7749a5ead1 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb @@ -133,7 +133,7 @@ def test_self_install_permissions_umask_0 def test_self_install_permissions_umask_077 umask = File.umask(0o077) - assert_self_install_permissions + assert_self_install_permissions(data_mode: 0o600) ensure File.umask(umask) end @@ -151,12 +151,12 @@ def test_self_install_permissions_with_format_executable_and_non_standard_ruby_i Gem::Installer.exec_format = nil end - def assert_self_install_permissions(format_executable: false) + def assert_self_install_permissions(format_executable: false, data_mode: 0o640) mask = Gem.win_platform? ? 0o700 : 0o777 options = { dir_mode: 0o500, prog_mode: Gem.win_platform? ? 0o410 : 0o510, - data_mode: 0o640, + data_mode: data_mode, wrappers: true, format_executable: format_executable, } diff --git a/test/win32ole/test_win32ole.rb b/test/win32ole/test_win32ole.rb index b0c147b3116c15..e6347e89b456ec 100644 --- a/test/win32ole/test_win32ole.rb +++ b/test/win32ole/test_win32ole.rb @@ -167,6 +167,11 @@ def test_s_new assert_instance_of(WIN32OLE, @dict2) end + def test_toplevel_constants_backward_compatibility + assert_equal(WIN32OLE::RuntimeError, ::WIN32OLERuntimeError) + assert_equal(WIN32OLE::QueryInterfaceError, ::WIN32OLEQueryInterfaceError) + end + def test_s_new_exc assert_raise(TypeError) { WIN32OLE.new(1) diff --git a/test/win32ole/test_win32ole_event.rb b/test/win32ole/test_win32ole_event.rb index da3ee8567e8ebb..d52f8cf9b3ba74 100644 --- a/test/win32ole/test_win32ole_event.rb +++ b/test/win32ole/test_win32ole_event.rb @@ -30,6 +30,10 @@ if defined?(WIN32OLE::Event) class TestWIN32OLE_EVENT < Test::Unit::TestCase + def test_toplevel_constants_backward_compatibility + assert_equal(WIN32OLE::Event, ::WIN32OLE_EVENT) + end + def test_s_new_exception assert_raise(TypeError) { WIN32OLE::Event.new("A") diff --git a/test/win32ole/test_win32ole_method.rb b/test/win32ole/test_win32ole_method.rb index 4b3e255fdc99fe..c84c4027ff3f00 100644 --- a/test/win32ole/test_win32ole_method.rb +++ b/test/win32ole/test_win32ole_method.rb @@ -20,6 +20,10 @@ def setup @m_file_name = WIN32OLE::Method.new(ole_type, "name") end + def test_toplevel_constants_backward_compatibility + assert_equal(WIN32OLE::Method, ::WIN32OLE_METHOD) + end + def test_initialize ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell") assert_raise(TypeError) { diff --git a/test/win32ole/test_win32ole_param.rb b/test/win32ole/test_win32ole_param.rb index 551da537fc7165..13ca9d0cfbea5f 100644 --- a/test/win32ole/test_win32ole_param.rb +++ b/test/win32ole/test_win32ole_param.rb @@ -27,6 +27,10 @@ def setup @param_key = m_add.params[0] end + def test_constants_backward_compatibility + assert_equal(WIN32OLE::Param, ::WIN32OLE_PARAM) + end + def test_s_new assert_raise(ArgumentError) { WIN32OLE::Param.new("hoge") diff --git a/test/win32ole/test_win32ole_record.rb b/test/win32ole/test_win32ole_record.rb index b2f26403bbcbed..49205ce53da91c 100644 --- a/test/win32ole/test_win32ole_record.rb +++ b/test/win32ole/test_win32ole_record.rb @@ -66,6 +66,12 @@ if defined?(WIN32OLE::Record) + class TestWIN32OLE_RECORD < Test::Unit::TestCase + def test_toplevel_constants_backward_compatibility + assert_equal(WIN32OLE::Record, ::WIN32OLE_RECORD) + end + end + def rbcomtest_exist? WIN32OLE.new(PROGID_RBCOMTEST) true diff --git a/test/win32ole/test_win32ole_type.rb b/test/win32ole/test_win32ole_type.rb index 32aafcbbad5db6..9abcd68c9bb5e0 100644 --- a/test/win32ole/test_win32ole_type.rb +++ b/test/win32ole/test_win32ole_type.rb @@ -7,6 +7,9 @@ if defined?(WIN32OLE::Type) class TestWIN32OLE_TYPE < Test::Unit::TestCase + def test_toplevel_constants_backward_compatibility + assert_equal(WIN32OLE::Type, ::WIN32OLE_TYPE) + end def test_s_progids progids = WIN32OLE::Type.progids diff --git a/test/win32ole/test_win32ole_typelib.rb b/test/win32ole/test_win32ole_typelib.rb index f743ad68f90e31..31d6122756be53 100644 --- a/test/win32ole/test_win32ole_typelib.rb +++ b/test/win32ole/test_win32ole_typelib.rb @@ -7,6 +7,10 @@ if defined?(WIN32OLE::TypeLib) class TestWIN32OLE_TYPELIB < Test::Unit::TestCase + def test_toplevel_constants_backward_compatibility + assert_equal(WIN32OLE::TypeLib, ::WIN32OLE_TYPELIB) + end + def test_s_typelibs tlibs = WIN32OLE::TypeLib.typelibs assert_instance_of(Array, tlibs) diff --git a/test/win32ole/test_win32ole_variable.rb b/test/win32ole/test_win32ole_variable.rb index 74a6cbd890ad95..646cf68915e3b0 100644 --- a/test/win32ole/test_win32ole_variable.rb +++ b/test/win32ole/test_win32ole_variable.rb @@ -16,6 +16,10 @@ def setup @var2 = variables.find {|v| v.name == 'UILevel'} end + def test_toplevel_constants_backward_compatibility + assert_equal(WIN32OLE::Variable, ::WIN32OLE_VARIABLE) + end + def test_initialize assert_raise(TypeError) {WIN32OLE::Variable.new} end diff --git a/test/win32ole/test_win32ole_variant.rb b/test/win32ole/test_win32ole_variant.rb index 1837a1e1d630f2..13b9a229a5076e 100644 --- a/test/win32ole/test_win32ole_variant.rb +++ b/test/win32ole/test_win32ole_variant.rb @@ -17,6 +17,10 @@ def teardown WIN32OLE.locale = @orglocale end + def test_toplevel_constants_backward_compatibility + assert_equal(WIN32OLE::Variant, ::WIN32OLE_VARIANT) + end + def test_s_new obj = WIN32OLE::Variant.new('foo') assert_instance_of(WIN32OLE::Variant, obj) diff --git a/test/win32ole/test_win32ole_variant_m.rb b/test/win32ole/test_win32ole_variant_m.rb index 25ad56cc21f976..3c2884644c5892 100644 --- a/test/win32ole/test_win32ole_variant_m.rb +++ b/test/win32ole/test_win32ole_variant_m.rb @@ -8,6 +8,11 @@ if defined?(WIN32OLE::VARIANT) class TestWin32OLE_VARIANT_MODULE < Test::Unit::TestCase include WIN32OLE::VARIANT + + def test_toplevel_constants_backward_compatibility + assert_equal(WIN32OLE::VariantType, WIN32OLE::VARIANT) + end + def test_variant assert_equal(0, VT_EMPTY) assert_equal(1, VT_NULL) diff --git a/thread.c b/thread.c index 58b0b8dd900501..48f3221b04b5c1 100644 --- a/thread.c +++ b/thread.c @@ -147,7 +147,7 @@ static int rb_threadptr_pending_interrupt_empty_p(const rb_thread_t *th); static const char *thread_status_name(rb_thread_t *th, int detail); static int hrtime_update_expire(rb_hrtime_t *, const rb_hrtime_t); NORETURN(static void async_bug_fd(const char *mesg, int errno_arg, int fd)); -static int consume_communication_pipe(int fd); +MAYBE_UNUSED(static int consume_communication_pipe(int fd)); static volatile int system_working = 1; static rb_internal_thread_specific_key_t specific_key_count; @@ -260,6 +260,8 @@ timeout_prepare(rb_hrtime_t **to, rb_hrtime_t *rel, rb_hrtime_t *end, } MAYBE_UNUSED(NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start))); +MAYBE_UNUSED(static bool th_has_dedicated_nt(const rb_thread_t *th)); +MAYBE_UNUSED(static int waitfd_to_waiting_flag(int wfd_event)); #include THREAD_IMPL_SRC @@ -526,9 +528,6 @@ void ruby_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame) { native_thread_init_stack(th, local_in_parent_frame); -#ifdef RUBY_ASAN_ENABLED - th->asan_fake_stack_handle = asan_get_thread_fake_stack_handle(); -#endif } const VALUE * diff --git a/thread_none.c b/thread_none.c index 76bdc9e200f09b..38730df7ba1ff2 100644 --- a/thread_none.c +++ b/thread_none.c @@ -46,10 +46,12 @@ rb_thread_sched_init(struct rb_thread_sched *sched, bool atfork) { } +#if 0 static void rb_thread_sched_destroy(struct rb_thread_sched *sched) { } +#endif // Do nothing for mutex guard void diff --git a/thread_pthread.c b/thread_pthread.c index d43633d7cc36b2..2981d57e37da03 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -2095,6 +2095,7 @@ native_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame) rb_nativethread_id_t curr = pthread_self(); #ifdef RUBY_ASAN_ENABLED local_in_parent_frame = asan_get_real_stack_addr(local_in_parent_frame); + th->ec->machine.asan_fake_stack_handle = asan_get_thread_fake_stack_handle(); #endif if (!native_main_thread.id) { diff --git a/thread_win32.c b/thread_win32.c index dd451c5e837e85..37bf823675f319 100644 --- a/thread_win32.c +++ b/thread_win32.c @@ -155,6 +155,7 @@ rb_thread_sched_init(struct rb_thread_sched *sched, bool atfork) sched->lock = w32_mutex_create(); } +#if 0 // per-ractor void rb_thread_sched_destroy(struct rb_thread_sched *sched) @@ -162,6 +163,7 @@ rb_thread_sched_destroy(struct rb_thread_sched *sched) if (GVL_DEBUG) fprintf(stderr, "sched destroy\n"); CloseHandle(sched->lock); } +#endif rb_thread_t * ruby_thread_from_native(void) diff --git a/time.c b/time.c index 6179b081c02fc9..3304b2f4f4856a 100644 --- a/time.c +++ b/time.c @@ -2346,7 +2346,7 @@ zone_timelocal(VALUE zone, VALUE time) struct time_object *tobj = RTYPEDDATA_GET_DATA(time); wideval_t t, s; - split_second(tobj->timew, &t, &s); + wdivmod(tobj->timew, WINT2FIXWV(TIME_SCALE), &t, &s); tm = tm_from_time(rb_cTimeTM, time); utc = rb_check_funcall(zone, id_local_to_utc, 1, &tm); if (UNDEF_P(utc)) return 0; diff --git a/tool/lrama/NEWS.md b/tool/lrama/NEWS.md index b5c26408de1f21..96aaaf94f57d5f 100644 --- a/tool/lrama/NEWS.md +++ b/tool/lrama/NEWS.md @@ -1,5 +1,109 @@ # NEWS for Lrama +## Lrama 0.6.5 (2024-03-25) + +### Typed Midrule Actions + +User can specify the type of mid rule action by tag (``) instead of specifying it with in an action. + +``` +primary: k_case expr_value terms? + { + $$ = p->case_labels; + p->case_labels = Qnil; + } + case_body + k_end + { + ... + } +``` + +can be written as + +``` +primary: k_case expr_value terms? + { + $$ = p->case_labels; + p->case_labels = Qnil; + } + case_body + k_end + { + ... + } +``` + +`%destructor` for midrule action is invoked only when tag is specified by Typed Midrule Actions. + +Difference from Bison's Typed Midrule Actions is that tag is postposed in Lrama however it's preposed in Bison. + +Bison supports this feature from 3.1. + +## Lrama 0.6.4 (2024-03-22) + +### Parameterizing rules (preceded, terminated, delimited) + +Support `preceded`, `terminated` and `delimited` rules. + +``` +program: preceded(opening, X) + +// Expanded to + +program: preceded_opening_X +preceded_opening_X: opening X +``` + +``` +program: terminated(X, closing) + +// Expanded to + +program: terminated_X_closing +terminated_X_closing: X closing +``` + +``` +program: delimited(opening, X, closing) + +// Expanded to + +program: delimited_opening_X_closing +delimited_opening_X_closing: opening X closing +``` + +https://github.com/ruby/lrama/pull/382 + +### Support `%destructor` declaration + +User can set codes for freeing semantic value resources by using `%destructor`. +In general, these resources are freed by actions or after parsing. +However if syntax error happens in parsing, these codes may not be executed. +Codes associated to `%destructor` are executed when semantic value is popped from the stack by an error. + +``` +%token NUM +%type expr2 +%type expr + +%destructor { + printf("destructor for val1: %d\n", $$); +} // printer for TAG + +%destructor { + printf("destructor for val2: %d\n", $$); +} + +%destructor { + printf("destructor for expr: %d\n", $$); +} expr // printer for symbol +``` + +Bison supports this feature from 1.75b. + +https://github.com/ruby/lrama/pull/385 + ## Lrama 0.6.3 (2024-02-15) ### Bring Your Own Stack @@ -34,6 +138,8 @@ primary: k_if expr_value then compstmt if_tail k_end } ``` +https://github.com/ruby/lrama/pull/367 + ## Lrama 0.6.2 (2024-01-27) ### %no-stdlib directive @@ -51,7 +157,7 @@ Allow to pass an instantiated rule to other parameterizing rules. ``` %rule constant(X) : X - ; + ; %rule option(Y) : /* empty */ | Y diff --git a/tool/lrama/lib/lrama/grammar.rb b/tool/lrama/lib/lrama/grammar.rb index 7ccde1aa89e4c2..a816b8261b368f 100644 --- a/tool/lrama/lib/lrama/grammar.rb +++ b/tool/lrama/lib/lrama/grammar.rb @@ -3,6 +3,7 @@ require "lrama/grammar/binding" require "lrama/grammar/code" require "lrama/grammar/counter" +require "lrama/grammar/destructor" require "lrama/grammar/error_token" require "lrama/grammar/parameterizing_rule" require "lrama/grammar/percent_code" @@ -34,7 +35,7 @@ class Grammar def_delegators "@symbols_resolver", :symbols, :nterms, :terms, :add_nterm, :add_term, :find_symbol_by_number!, :find_symbol_by_id!, :token_to_symbol, :find_symbol_by_s_value!, :fill_symbol_number, :fill_nterm_type, - :fill_printer, :fill_error_token, :sort_by_number! + :fill_printer, :fill_destructor, :fill_error_token, :sort_by_number! def initialize(rule_counter) @@ -43,6 +44,7 @@ def initialize(rule_counter) # Code defined by "%code" @percent_codes = [] @printers = [] + @destructors = [] @error_tokens = [] @symbols_resolver = Grammar::Symbols::Resolver.new @types = [] @@ -65,6 +67,10 @@ def add_percent_code(id:, code:) @percent_codes << PercentCode.new(id.s_value, code.s_value) end + def add_destructor(ident_or_tags:, token_code:, lineno:) + @destructors << Destructor.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno) + end + def add_printer(ident_or_tags:, token_code:, lineno:) @printers << Printer.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno) end @@ -345,6 +351,7 @@ def fill_symbols fill_symbol_number fill_nterm_type(@types) fill_printer(@printers) + fill_destructor(@destructors) fill_error_token(@error_tokens) sort_by_number! end diff --git a/tool/lrama/lib/lrama/grammar/code.rb b/tool/lrama/lib/lrama/grammar/code.rb index e108d91c7f2af4..3bad599dae564f 100644 --- a/tool/lrama/lib/lrama/grammar/code.rb +++ b/tool/lrama/lib/lrama/grammar/code.rb @@ -1,4 +1,5 @@ require "forwardable" +require "lrama/grammar/code/destructor_code" require "lrama/grammar/code/initial_action_code" require "lrama/grammar/code/no_reference_code" require "lrama/grammar/code/printer_code" diff --git a/tool/lrama/lib/lrama/grammar/code/destructor_code.rb b/tool/lrama/lib/lrama/grammar/code/destructor_code.rb new file mode 100644 index 00000000000000..70360eb90fab38 --- /dev/null +++ b/tool/lrama/lib/lrama/grammar/code/destructor_code.rb @@ -0,0 +1,40 @@ +module Lrama + class Grammar + class Code + class DestructorCode < Code + def initialize(type:, token_code:, tag:) + super(type: type, token_code: token_code) + @tag = tag + end + + private + + # * ($$) *yyvaluep + # * (@$) *yylocationp + # * ($:$) error + # * ($1) error + # * (@1) error + # * ($:1) error + def reference_to_c(ref) + case + when ref.type == :dollar && ref.name == "$" # $$ + member = @tag.member + "((*yyvaluep).#{member})" + when ref.type == :at && ref.name == "$" # @$ + "(*yylocationp)" + when ref.type == :index && ref.name == "$" # $:$ + raise "$:#{ref.value} can not be used in #{type}." + when ref.type == :dollar # $n + raise "$#{ref.value} can not be used in #{type}." + when ref.type == :at # @n + raise "@#{ref.value} can not be used in #{type}." + when ref.type == :index # $:n + raise "$:#{ref.value} can not be used in #{type}." + else + raise "Unexpected. #{self}, #{ref}" + end + end + end + end + end +end diff --git a/tool/lrama/lib/lrama/grammar/destructor.rb b/tool/lrama/lib/lrama/grammar/destructor.rb new file mode 100644 index 00000000000000..4b7059e9236ccb --- /dev/null +++ b/tool/lrama/lib/lrama/grammar/destructor.rb @@ -0,0 +1,9 @@ +module Lrama + class Grammar + class Destructor < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true) + def translated_code(tag) + Code::DestructorCode.new(type: :destructor, token_code: token_code, tag: tag).translated_code + end + end + end +end diff --git a/tool/lrama/lib/lrama/grammar/rule_builder.rb b/tool/lrama/lib/lrama/grammar/rule_builder.rb index 3cbaab5bcca3cd..b2ccc3e2437b8c 100644 --- a/tool/lrama/lib/lrama/grammar/rule_builder.rb +++ b/tool/lrama/lib/lrama/grammar/rule_builder.rb @@ -115,12 +115,12 @@ def process_rhs(parameterizing_rule_resolver) @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, i, lhs_tag: token.lhs_tag, skip_preprocess_references: true) + rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, lhs_tag: token.lhs_tag, skip_preprocess_references: true) rule_builder.lhs = lhs_token r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) } rule_builder.line = line - rule_builder.user_code = r.user_code rule_builder.precedence_sym = r.precedence_sym + rule_builder.user_code = r.user_code rule_builder.complete_input rule_builder.setup_rules(parameterizing_rule_resolver) @rule_builders_for_parameterizing_rules << rule_builder @@ -128,10 +128,11 @@ def process_rhs(parameterizing_rule_resolver) end when Lrama::Lexer::Token::UserCode prefix = token.referred ? "@" : "$@" + tag = token.tag || lhs_tag new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s) @replaced_rhs << new_token - rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, i, lhs_tag: lhs_tag, skip_preprocess_references: true) + rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, i, lhs_tag: tag, skip_preprocess_references: true) rule_builder.lhs = new_token rule_builder.user_code = token rule_builder.complete_input diff --git a/tool/lrama/lib/lrama/grammar/stdlib.y b/tool/lrama/lib/lrama/grammar/stdlib.y index f2dfba07336daf..d6e89c908c5139 100644 --- a/tool/lrama/lib/lrama/grammar/stdlib.y +++ b/tool/lrama/lib/lrama/grammar/stdlib.y @@ -8,6 +8,9 @@ **********************************************************************/ +// ------------------------------------------------------------------- +// Options + /* * program: option(number) * @@ -21,6 +24,45 @@ | X ; +// ------------------------------------------------------------------- +// Sequences + +/* + * program: preceded(opening, X) + * + * => + * + * program: preceded_opening_X + * preceded_opening_X: opening X + */ +%rule preceded(opening, X): opening X { $$ = $2; } + ; + +/* + * program: terminated(X, closing) + * + * => + * + * program: terminated_X_closing + * terminated_X_closing: X closing + */ +%rule terminated(X, closing): X closing { $$ = $1; } + ; + +/* + * program: delimited(opening, X, closing) + * + * => + * + * program: delimited_opening_X_closing + * delimited_opening_X_closing: opening X closing + */ +%rule delimited(opening, X, closing): opening X closing { $$ = $2; } + ; + +// ------------------------------------------------------------------- +// Lists + /* * program: list(number) * diff --git a/tool/lrama/lib/lrama/grammar/symbol.rb b/tool/lrama/lib/lrama/grammar/symbol.rb index 21765226c06439..deb67ad9a82c32 100644 --- a/tool/lrama/lib/lrama/grammar/symbol.rb +++ b/tool/lrama/lib/lrama/grammar/symbol.rb @@ -7,11 +7,12 @@ module Lrama class Grammar class Symbol - attr_accessor :id, :alias_name, :tag, :number, :token_id, :nullable, :precedence, :printer, :error_token, :first_set, :first_set_bitmap + attr_accessor :id, :alias_name, :tag, :number, :token_id, :nullable, :precedence, + :printer, :destructor, :error_token, :first_set, :first_set_bitmap attr_reader :term attr_writer :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol - def initialize(id:, term:, alias_name: nil, number: nil, tag: nil, token_id: nil, nullable: nil, precedence: nil, printer: nil) + def initialize(id:, term:, alias_name: nil, number: nil, tag: nil, token_id: nil, nullable: nil, precedence: nil, printer: nil, destructor: nil) @id = id @alias_name = alias_name @number = number @@ -21,6 +22,7 @@ def initialize(id:, term:, alias_name: nil, number: nil, tag: nil, token_id: nil @nullable = nullable @precedence = precedence @printer = printer + @destructor = destructor end def term? diff --git a/tool/lrama/lib/lrama/grammar/symbols/resolver.rb b/tool/lrama/lib/lrama/grammar/symbols/resolver.rb index 07e03e70a96a2e..1788ed63fabbc5 100644 --- a/tool/lrama/lib/lrama/grammar/symbols/resolver.rb +++ b/tool/lrama/lib/lrama/grammar/symbols/resolver.rb @@ -58,7 +58,7 @@ def find_symbol_by_s_value(s_value) end def find_symbol_by_s_value!(s_value) - find_symbol_by_s_value(s_value) || (raise "Symbol not found: #{s_value}") + find_symbol_by_s_value(s_value) || (raise "Symbol not found. value: `#{s_value}`") end def find_symbol_by_id(id) @@ -68,7 +68,7 @@ def find_symbol_by_id(id) end def find_symbol_by_id!(id) - find_symbol_by_id(id) || (raise "Symbol not found: #{id}") + find_symbol_by_id(id) || (raise "Symbol not found. #{id}") end def find_symbol_by_token_id(token_id) @@ -78,7 +78,7 @@ def find_symbol_by_token_id(token_id) def find_symbol_by_number!(number) sym = symbols[number] - raise "Symbol not found: #{number}" unless sym + raise "Symbol not found. number: `#{number}`" unless sym raise "[BUG] Symbol number mismatch. #{number}, #{sym}" if sym.number != number sym @@ -118,6 +118,23 @@ def fill_printer(printers) end end + def fill_destructor(destructors) + symbols.each do |sym| + destructors.each do |destructor| + destructor.ident_or_tags.each do |ident_or_tag| + case ident_or_tag + when Lrama::Lexer::Token::Ident + sym.destructor = destructor if sym.id == ident_or_tag + when Lrama::Lexer::Token::Tag + sym.destructor = destructor if sym.tag == ident_or_tag + else + raise "Unknown token type. #{destructor}" + end + end + end + end + end + def fill_error_token(error_tokens) symbols.each do |sym| error_tokens.each do |token| @@ -154,7 +171,7 @@ def validate! def find_nterm_by_id!(id) @nterms.find do |s| s.id == id - end || (raise "Symbol not found: #{id}") + end || (raise "Symbol not found. #{id}") end def fill_terms_number diff --git a/tool/lrama/lib/lrama/lexer.rb b/tool/lrama/lib/lrama/lexer.rb index 33f37eb6058dec..db8f384fe6d272 100644 --- a/tool/lrama/lib/lrama/lexer.rb +++ b/tool/lrama/lib/lrama/lexer.rb @@ -21,6 +21,7 @@ class Lexer %define %require %printer + %destructor %lex-param %parse-param %initial-action diff --git a/tool/lrama/lib/lrama/lexer/token.rb b/tool/lrama/lib/lrama/lexer/token.rb index 5278e98725b297..59b49d5fba4f72 100644 --- a/tool/lrama/lib/lrama/lexer/token.rb +++ b/tool/lrama/lib/lrama/lexer/token.rb @@ -18,7 +18,7 @@ def initialize(s_value:, alias_name: nil, location: nil) end def to_s - "#{super} location: #{location}" + "value: `#{s_value}`, location: #{location}" end def referred_by?(string) diff --git a/tool/lrama/lib/lrama/lexer/token/user_code.rb b/tool/lrama/lib/lrama/lexer/token/user_code.rb index 14c69f3de6b423..4d487bf01cee4e 100644 --- a/tool/lrama/lib/lrama/lexer/token/user_code.rb +++ b/tool/lrama/lib/lrama/lexer/token/user_code.rb @@ -4,6 +4,8 @@ module Lrama class Lexer class Token class UserCode < Token + attr_accessor :tag + def references @references ||= _references end diff --git a/tool/lrama/lib/lrama/option_parser.rb b/tool/lrama/lib/lrama/option_parser.rb index 560b269b06d04a..3210b091ed7531 100644 --- a/tool/lrama/lib/lrama/option_parser.rb +++ b/tool/lrama/lib/lrama/option_parser.rb @@ -64,9 +64,18 @@ def parse_by_option_parser(argv) o.on('-H', '--header=[FILE]', 'also produce a header file named FILE') {|v| @options.header = true; @options.header_file = v } o.on('-d', 'also produce a header file') { @options.header = true } o.on('-r', '--report=THINGS', Array, 'also produce details on the automaton') {|v| @report = v } + o.on_tail '' + o.on_tail 'Valid Reports:' + o.on_tail " #{VALID_REPORTS.join(' ')}" + o.on('--report-file=FILE', 'also produce details on the automaton output to a file named FILE') {|v| @options.report_file = v } o.on('-o', '--output=FILE', 'leave output to FILE') {|v| @options.outfile = v } + o.on('--trace=THINGS', Array, 'also output trace logs at runtime') {|v| @trace = v } + o.on_tail '' + o.on_tail 'Valid Traces:' + o.on_tail " #{VALID_TRACES.join(' ')}" + o.on('-v', 'reserved, do nothing') { } o.separator '' o.separator 'Error Recovery:' @@ -75,20 +84,22 @@ def parse_by_option_parser(argv) o.separator 'Other options:' o.on('-V', '--version', "output version information and exit") {|v| puts "lrama #{Lrama::VERSION}"; exit 0 } o.on('-h', '--help', "display this help and exit") {|v| puts o; exit 0 } - o.separator '' + o.on_tail o.parse!(argv) end end + BISON_REPORTS = %w[states itemsets lookaheads solved counterexamples cex all none] + OTHER_REPORTS = %w[verbose] + NOT_SUPPORTED_REPORTS = %w[cex none] + VALID_REPORTS = BISON_REPORTS + OTHER_REPORTS - NOT_SUPPORTED_REPORTS + def validate_report(report) - bison_list = %w[states itemsets lookaheads solved counterexamples cex all none] - others = %w[verbose] - list = bison_list + others - not_supported = %w[cex none] + list = VALID_REPORTS h = { grammar: true } report.each do |r| - if list.include?(r) && !not_supported.include?(r) + if list.include?(r) h[r.to_sym] = true else raise "Invalid report option \"#{r}\"." @@ -96,7 +107,7 @@ def validate_report(report) end if h[:all] - (bison_list - not_supported).each do |r| + (BISON_REPORTS - NOT_SUPPORTED_REPORTS).each do |r| h[r.to_sym] = true end @@ -106,12 +117,14 @@ def validate_report(report) return h end + VALID_TRACES = %w[ + none locations scan parse automaton bitsets + closure grammar rules resource sets muscles tools + m4-early m4 skeleton time ielr cex all + ] + def validate_trace(trace) - list = %w[ - none locations scan parse automaton bitsets - closure grammar rules resource sets muscles tools - m4-early m4 skeleton time ielr cex all - ] + list = VALID_TRACES h = {} trace.each do |t| diff --git a/tool/lrama/lib/lrama/options.rb b/tool/lrama/lib/lrama/options.rb index e63679bcf2eda9..739ca16f5598f9 100644 --- a/tool/lrama/lib/lrama/options.rb +++ b/tool/lrama/lib/lrama/options.rb @@ -18,6 +18,7 @@ def initialize @trace_opts = nil @report_opts = nil @y = STDIN + @debug = false end end end diff --git a/tool/lrama/lib/lrama/output.rb b/tool/lrama/lib/lrama/output.rb index 29bf1e69fbedf6..642c8b4708f07c 100644 --- a/tool/lrama/lib/lrama/output.rb +++ b/tool/lrama/lib/lrama/output.rb @@ -150,6 +150,25 @@ def symbol_actions_for_printer str end + def symbol_actions_for_destructor + str = "" + + @grammar.symbols.each do |sym| + next unless sym.destructor + + str << <<-STR + case #{sym.enum_name}: /* #{sym.comment} */ +#line #{sym.destructor.lineno} "#{@grammar_file_path}" + {#{sym.destructor.translated_code(sym.tag)}} +#line [@oline@] [@ofile@] + break; + + STR + end + + str + end + # b4_user_initial_action def user_initial_action(comment = "") return "" unless @grammar.initial_action diff --git a/tool/lrama/lib/lrama/parser.rb b/tool/lrama/lib/lrama/parser.rb index 148457f1ddc925..0a46f759c0c787 100644 --- a/tool/lrama/lib/lrama/parser.rb +++ b/tool/lrama/lib/lrama/parser.rb @@ -658,7 +658,7 @@ def token_to_str(t) module Lrama class Parser < Racc::Parser -module_eval(<<'...end parser.y/module_eval...', 'parser.y', 521) +module_eval(<<'...end parser.y/module_eval...', 'parser.y', 529) include Lrama::Report::Duration @@ -759,7 +759,7 @@ def raise_parse_error(error_message, location) 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, 223, 94 ] + 189, 94, 194, 216, 218, 94, 194, 224, 94 ] racc_action_check = [ 48, 141, 48, 141, 140, 141, 170, 188, 170, 188, @@ -789,7 +789,7 @@ def raise_parse_error(error_message, location) 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, 222, 223 ] + 197, 198, 203, 206, 211, 216, 220, 222, 224 ] racc_action_pointer = [ nil, 20, 9, 26, 97, nil, nil, 23, nil, 32, @@ -814,10 +814,10 @@ def raise_parse_error(error_message, location) 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, - nil, nil, 256, 227, nil ] + 268, nil, 257, nil, 228, nil ] racc_action_default = [ - -2, -136, -8, -136, -136, -3, -4, -136, 225, -136, + -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, @@ -839,58 +839,56 @@ def raise_parse_error(error_message, location) -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, - -109, -64, -136, -118, -67 ] + -134, -64, -136, -109, -118, -67 ] racc_goto_table = [ - 93, 51, 73, 68, 116, 75, 108, 173, 193, 1, - 188, 196, 2, 191, 117, 196, 196, 141, 4, 71, - 41, 83, 83, 83, 83, 42, 79, 84, 85, 86, - 52, 54, 55, 181, 185, 186, 89, 5, 214, 207, - 109, 116, 205, 114, 213, 113, 75, 108, 135, 209, - 170, 39, 217, 119, 10, 71, 71, 90, 11, 116, - 12, 48, 95, 125, 162, 102, 147, 83, 83, 108, - 103, 148, 104, 149, 105, 150, 106, 151, 131, 67, - 72, 134, 110, 132, 75, 136, 113, 187, 211, 222, - 123, 160, 100, 145, 71, 140, 71, 177, 206, 120, - nil, nil, 83, nil, 83, nil, 113, nil, nil, nil, - nil, nil, 172, 157, nil, nil, nil, nil, 71, nil, - nil, nil, 83, nil, nil, nil, nil, nil, 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, 208, nil, nil, nil, nil, nil, nil, - 198, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, 220, nil, 212, 192, nil, 215, nil, 224, 198, - nil, nil, 192 ] + 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 ] racc_goto_check = [ - 41, 34, 46, 32, 53, 40, 33, 42, 59, 1, - 39, 63, 2, 43, 52, 63, 63, 58, 3, 34, - 4, 34, 34, 34, 34, 54, 31, 31, 31, 31, - 14, 14, 14, 20, 20, 20, 5, 6, 59, 39, - 32, 53, 42, 46, 43, 40, 40, 33, 52, 42, - 58, 7, 43, 8, 9, 34, 34, 54, 10, 53, - 11, 12, 13, 15, 16, 17, 18, 34, 34, 33, - 21, 22, 23, 24, 25, 26, 27, 28, 32, 29, - 30, 46, 35, 36, 40, 37, 40, 38, 44, 45, - 48, 49, 50, 51, 34, 57, 34, 60, 61, 62, - nil, nil, 34, nil, 34, nil, 40, nil, nil, nil, - nil, nil, 41, 40, nil, nil, nil, nil, 34, nil, - nil, nil, 34, nil, nil, nil, nil, nil, 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, 41, nil, nil, nil, nil, nil, nil, - 40, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, 41, nil, 40, 40, nil, 40, nil, 41, 40, - nil, nil, 40 ] + 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 ] racc_goto_pointer = [ - nil, 9, 12, 16, 11, -5, 35, 45, -35, 50, - 54, 56, 47, 14, 15, -38, -82, 8, -60, nil, - -132, 12, -56, 13, -55, 14, -54, 15, -53, 47, - 47, -8, -29, -62, -13, 11, -27, -33, -81, -158, - -28, -45, -150, -158, -112, -129, -31, nil, -9, -53, - 39, -31, -67, -76, 16, nil, nil, -26, -104, -165, - -61, -97, 8, -170 ] + 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 ] racc_goto_default = [ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, @@ -933,7 +931,7 @@ def raise_parse_error(error_message, location) 1, 63, :_reduce_none, 0, 76, :_reduce_29, 0, 77, :_reduce_30, - 7, 63, :_reduce_none, + 7, 63, :_reduce_31, 0, 78, :_reduce_32, 0, 79, :_reduce_33, 7, 63, :_reduce_34, @@ -1011,7 +1009,7 @@ def raise_parse_error(error_message, location) 6, 111, :_reduce_106, 0, 113, :_reduce_107, 0, 114, :_reduce_108, - 7, 111, :_reduce_109, + 8, 111, :_reduce_109, 3, 111, :_reduce_110, 1, 95, :_reduce_111, 1, 95, :_reduce_112, @@ -1041,7 +1039,7 @@ def raise_parse_error(error_message, location) racc_reduce_n = 136 -racc_shift_n = 225 +racc_shift_n = 226 racc_token_table = { false => 0, @@ -1424,9 +1422,19 @@ def _reduce_30(val, _values, result) end .,., -# reduce 31 omitted +module_eval(<<'.,.,', 'parser.y', 100) + def _reduce_31(val, _values, result) + @grammar.add_destructor( + ident_or_tags: val[6], + token_code: val[3], + lineno: val[3].line + ) -module_eval(<<'.,.,', 'parser.y', 101) + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 108) def _reduce_32(val, _values, result) begin_c_declaration("}") @@ -1434,7 +1442,7 @@ def _reduce_32(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 105) +module_eval(<<'.,.,', 'parser.y', 112) def _reduce_33(val, _values, result) end_c_declaration @@ -1442,7 +1450,7 @@ def _reduce_33(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 109) +module_eval(<<'.,.,', 'parser.y', 116) def _reduce_34(val, _values, result) @grammar.add_printer( ident_or_tags: val[6], @@ -1454,7 +1462,7 @@ def _reduce_34(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 117) +module_eval(<<'.,.,', 'parser.y', 124) def _reduce_35(val, _values, result) begin_c_declaration("}") @@ -1462,7 +1470,7 @@ def _reduce_35(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 121) +module_eval(<<'.,.,', 'parser.y', 128) def _reduce_36(val, _values, result) end_c_declaration @@ -1470,7 +1478,7 @@ def _reduce_36(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 125) +module_eval(<<'.,.,', 'parser.y', 132) def _reduce_37(val, _values, result) @grammar.add_error_token( ident_or_tags: val[6], @@ -1482,7 +1490,7 @@ def _reduce_37(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 133) +module_eval(<<'.,.,', 'parser.y', 140) def _reduce_38(val, _values, result) @grammar.after_shift = val[1] @@ -1490,7 +1498,7 @@ def _reduce_38(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 137) +module_eval(<<'.,.,', 'parser.y', 144) def _reduce_39(val, _values, result) @grammar.before_reduce = val[1] @@ -1498,7 +1506,7 @@ def _reduce_39(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 141) +module_eval(<<'.,.,', 'parser.y', 148) def _reduce_40(val, _values, result) @grammar.after_reduce = val[1] @@ -1506,7 +1514,7 @@ def _reduce_40(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 145) +module_eval(<<'.,.,', 'parser.y', 152) def _reduce_41(val, _values, result) @grammar.after_shift_error_token = val[1] @@ -1514,7 +1522,7 @@ def _reduce_41(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 149) +module_eval(<<'.,.,', 'parser.y', 156) def _reduce_42(val, _values, result) @grammar.after_pop_stack = val[1] @@ -1524,7 +1532,7 @@ def _reduce_42(val, _values, result) # reduce 43 omitted -module_eval(<<'.,.,', 'parser.y', 155) +module_eval(<<'.,.,', 'parser.y', 162) def _reduce_44(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| @@ -1536,7 +1544,7 @@ def _reduce_44(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 163) +module_eval(<<'.,.,', 'parser.y', 170) def _reduce_45(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| @@ -1550,7 +1558,7 @@ def _reduce_45(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 173) +module_eval(<<'.,.,', 'parser.y', 180) def _reduce_46(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| @@ -1564,7 +1572,7 @@ def _reduce_46(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 183) +module_eval(<<'.,.,', 'parser.y', 190) def _reduce_47(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| @@ -1578,7 +1586,7 @@ def _reduce_47(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 193) +module_eval(<<'.,.,', 'parser.y', 200) def _reduce_48(val, _values, result) val[1].each {|hash| hash[:tokens].each {|id| @@ -1592,7 +1600,7 @@ def _reduce_48(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 204) +module_eval(<<'.,.,', 'parser.y', 211) def _reduce_49(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) @@ -1602,7 +1610,7 @@ def _reduce_49(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 210) +module_eval(<<'.,.,', 'parser.y', 217) def _reduce_50(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) @@ -1612,7 +1620,7 @@ def _reduce_50(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 216) +module_eval(<<'.,.,', 'parser.y', 223) def _reduce_51(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) @@ -1622,28 +1630,28 @@ def _reduce_51(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 221) +module_eval(<<'.,.,', 'parser.y', 228) def _reduce_52(val, _values, result) result = [val[0]] result end .,., -module_eval(<<'.,.,', 'parser.y', 222) +module_eval(<<'.,.,', 'parser.y', 229) def _reduce_53(val, _values, result) result = val[0].append(val[1]) result end .,., -module_eval(<<'.,.,', 'parser.y', 224) +module_eval(<<'.,.,', 'parser.y', 231) def _reduce_54(val, _values, result) result = val result end .,., -module_eval(<<'.,.,', 'parser.y', 228) +module_eval(<<'.,.,', 'parser.y', 235) def _reduce_55(val, _values, result) rule = Grammar::ParameterizingRule::Rule.new(val[1].s_value, val[3], val[6]) @grammar.add_parameterizing_rule(rule) @@ -1652,21 +1660,21 @@ def _reduce_55(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 232) +module_eval(<<'.,.,', 'parser.y', 239) def _reduce_56(val, _values, result) result = [val[0]] result end .,., -module_eval(<<'.,.,', 'parser.y', 233) +module_eval(<<'.,.,', 'parser.y', 240) def _reduce_57(val, _values, result) result = val[0].append(val[2]) result end .,., -module_eval(<<'.,.,', 'parser.y', 237) +module_eval(<<'.,.,', 'parser.y', 244) def _reduce_58(val, _values, result) builder = val[0] result = [builder] @@ -1675,7 +1683,7 @@ def _reduce_58(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 242) +module_eval(<<'.,.,', 'parser.y', 249) def _reduce_59(val, _values, result) builder = val[2] result = val[0].append(builder) @@ -1684,7 +1692,7 @@ def _reduce_59(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 248) +module_eval(<<'.,.,', 'parser.y', 255) def _reduce_60(val, _values, result) reset_precs result = Grammar::ParameterizingRule::Rhs.new @@ -1693,7 +1701,7 @@ def _reduce_60(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 253) +module_eval(<<'.,.,', 'parser.y', 260) def _reduce_61(val, _values, result) reset_precs result = Grammar::ParameterizingRule::Rhs.new @@ -1702,7 +1710,7 @@ def _reduce_61(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 258) +module_eval(<<'.,.,', 'parser.y', 265) def _reduce_62(val, _values, result) token = val[1] token.alias_name = val[2] @@ -1714,7 +1722,7 @@ def _reduce_62(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 266) +module_eval(<<'.,.,', 'parser.y', 273) def _reduce_63(val, _values, result) builder = val[0] builder.symbols << Lrama::Lexer::Token::InstantiateRule.new(s_value: val[2], location: @lexer.location, args: [val[1]]) @@ -1724,7 +1732,7 @@ def _reduce_63(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 272) +module_eval(<<'.,.,', 'parser.y', 279) def _reduce_64(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]) @@ -1734,7 +1742,7 @@ def _reduce_64(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 278) +module_eval(<<'.,.,', 'parser.y', 285) def _reduce_65(val, _values, result) if @prec_seen on_action_error("multiple User_code after %prec", val[0]) if @code_after_prec @@ -1746,7 +1754,7 @@ def _reduce_65(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 286) +module_eval(<<'.,.,', 'parser.y', 293) def _reduce_66(val, _values, result) end_c_declaration @@ -1754,7 +1762,7 @@ def _reduce_66(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 290) +module_eval(<<'.,.,', 'parser.y', 297) def _reduce_67(val, _values, result) user_code = val[3] user_code.alias_name = val[6] @@ -1766,7 +1774,7 @@ def _reduce_67(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 298) +module_eval(<<'.,.,', 'parser.y', 305) def _reduce_68(val, _values, result) sym = @grammar.find_symbol_by_id!(val[2]) @prec_seen = true @@ -1786,7 +1794,7 @@ def _reduce_68(val, _values, result) # reduce 72 omitted -module_eval(<<'.,.,', 'parser.y', 313) +module_eval(<<'.,.,', 'parser.y', 320) def _reduce_73(val, _values, result) result = [{tag: nil, tokens: val[0]}] @@ -1794,7 +1802,7 @@ def _reduce_73(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 317) +module_eval(<<'.,.,', 'parser.y', 324) def _reduce_74(val, _values, result) result = [{tag: val[0], tokens: val[1]}] @@ -1802,7 +1810,7 @@ def _reduce_74(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 321) +module_eval(<<'.,.,', 'parser.y', 328) def _reduce_75(val, _values, result) result = val[0].append({tag: val[1], tokens: val[2]}) @@ -1810,14 +1818,14 @@ def _reduce_75(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 324) +module_eval(<<'.,.,', 'parser.y', 331) def _reduce_76(val, _values, result) result = [val[0]] result end .,., -module_eval(<<'.,.,', 'parser.y', 325) +module_eval(<<'.,.,', 'parser.y', 332) def _reduce_77(val, _values, result) result = val[0].append(val[1]) result @@ -1828,7 +1836,7 @@ def _reduce_77(val, _values, result) # reduce 79 omitted -module_eval(<<'.,.,', 'parser.y', 332) +module_eval(<<'.,.,', 'parser.y', 339) def _reduce_80(val, _values, result) begin_c_declaration("}") @@ -1836,7 +1844,7 @@ def _reduce_80(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 336) +module_eval(<<'.,.,', 'parser.y', 343) def _reduce_81(val, _values, result) end_c_declaration @@ -1844,7 +1852,7 @@ def _reduce_81(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 340) +module_eval(<<'.,.,', 'parser.y', 347) def _reduce_82(val, _values, result) result = val[0].append(val[3]) @@ -1852,7 +1860,7 @@ def _reduce_82(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 344) +module_eval(<<'.,.,', 'parser.y', 351) def _reduce_83(val, _values, result) begin_c_declaration("}") @@ -1860,7 +1868,7 @@ def _reduce_83(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 348) +module_eval(<<'.,.,', 'parser.y', 355) def _reduce_84(val, _values, result) end_c_declaration @@ -1868,7 +1876,7 @@ def _reduce_84(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 352) +module_eval(<<'.,.,', 'parser.y', 359) def _reduce_85(val, _values, result) result = [val[2]] @@ -1876,7 +1884,7 @@ def _reduce_85(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 357) +module_eval(<<'.,.,', 'parser.y', 364) def _reduce_86(val, _values, result) result = [{tag: nil, tokens: val[0]}] @@ -1884,7 +1892,7 @@ def _reduce_86(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 361) +module_eval(<<'.,.,', 'parser.y', 368) def _reduce_87(val, _values, result) result = [{tag: val[0], tokens: val[1]}] @@ -1892,7 +1900,7 @@ def _reduce_87(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 365) +module_eval(<<'.,.,', 'parser.y', 372) def _reduce_88(val, _values, result) result = val[0].append({tag: val[1], tokens: val[2]}) @@ -1900,14 +1908,14 @@ def _reduce_88(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 368) +module_eval(<<'.,.,', 'parser.y', 375) def _reduce_89(val, _values, result) result = [val[0]] result end .,., -module_eval(<<'.,.,', 'parser.y', 369) +module_eval(<<'.,.,', 'parser.y', 376) def _reduce_90(val, _values, result) result = val[0].append(val[1]) result @@ -1916,14 +1924,14 @@ def _reduce_90(val, _values, result) # reduce 91 omitted -module_eval(<<'.,.,', 'parser.y', 373) +module_eval(<<'.,.,', 'parser.y', 380) def _reduce_92(val, _values, result) on_action_error("ident after %prec", val[0]) if @prec_seen result end .,., -module_eval(<<'.,.,', 'parser.y', 374) +module_eval(<<'.,.,', 'parser.y', 381) def _reduce_93(val, _values, result) on_action_error("char after %prec", val[0]) if @prec_seen result @@ -1938,7 +1946,7 @@ def _reduce_93(val, _values, result) # reduce 97 omitted -module_eval(<<'.,.,', 'parser.y', 384) +module_eval(<<'.,.,', 'parser.y', 391) def _reduce_98(val, _values, result) lhs = val[0] lhs.alias_name = val[1] @@ -1952,7 +1960,7 @@ def _reduce_98(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 395) +module_eval(<<'.,.,', 'parser.y', 402) def _reduce_99(val, _values, result) builder = val[0] if !builder.line @@ -1964,7 +1972,7 @@ def _reduce_99(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 403) +module_eval(<<'.,.,', 'parser.y', 410) def _reduce_100(val, _values, result) builder = val[2] if !builder.line @@ -1978,7 +1986,7 @@ def _reduce_100(val, _values, result) # reduce 101 omitted -module_eval(<<'.,.,', 'parser.y', 413) +module_eval(<<'.,.,', 'parser.y', 420) def _reduce_102(val, _values, result) reset_precs result = Grammar::RuleBuilder.new(@rule_counter, @midrule_action_counter) @@ -1987,7 +1995,7 @@ def _reduce_102(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 418) +module_eval(<<'.,.,', 'parser.y', 425) def _reduce_103(val, _values, result) reset_precs result = Grammar::RuleBuilder.new(@rule_counter, @midrule_action_counter) @@ -1996,7 +2004,7 @@ def _reduce_103(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 423) +module_eval(<<'.,.,', 'parser.y', 430) def _reduce_104(val, _values, result) token = val[1] token.alias_name = val[2] @@ -2008,7 +2016,7 @@ def _reduce_104(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 431) +module_eval(<<'.,.,', 'parser.y', 438) def _reduce_105(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] @@ -2020,7 +2028,7 @@ def _reduce_105(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 439) +module_eval(<<'.,.,', 'parser.y', 446) def _reduce_106(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] @@ -2032,7 +2040,7 @@ def _reduce_106(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 447) +module_eval(<<'.,.,', 'parser.y', 454) def _reduce_107(val, _values, result) if @prec_seen on_action_error("multiple User_code after %prec", val[0]) if @code_after_prec @@ -2044,7 +2052,7 @@ def _reduce_107(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 455) +module_eval(<<'.,.,', 'parser.y', 462) def _reduce_108(val, _values, result) end_c_declaration @@ -2052,10 +2060,11 @@ def _reduce_108(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 459) +module_eval(<<'.,.,', 'parser.y', 466) def _reduce_109(val, _values, result) user_code = val[3] user_code.alias_name = val[6] + user_code.tag = val[7] builder = val[0] builder.user_code = user_code result = builder @@ -2064,7 +2073,7 @@ def _reduce_109(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 467) +module_eval(<<'.,.,', 'parser.y', 475) def _reduce_110(val, _values, result) sym = @grammar.find_symbol_by_id!(val[2]) @prec_seen = true @@ -2076,49 +2085,49 @@ def _reduce_110(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 474) +module_eval(<<'.,.,', 'parser.y', 482) def _reduce_111(val, _values, result) result = "option" result end .,., -module_eval(<<'.,.,', 'parser.y', 475) +module_eval(<<'.,.,', 'parser.y', 483) def _reduce_112(val, _values, result) result = "nonempty_list" result end .,., -module_eval(<<'.,.,', 'parser.y', 476) +module_eval(<<'.,.,', 'parser.y', 484) def _reduce_113(val, _values, result) result = "list" result end .,., -module_eval(<<'.,.,', 'parser.y', 478) +module_eval(<<'.,.,', 'parser.y', 486) def _reduce_114(val, _values, result) result = [val[0]] result end .,., -module_eval(<<'.,.,', 'parser.y', 479) +module_eval(<<'.,.,', 'parser.y', 487) def _reduce_115(val, _values, result) result = val[0].append(val[2]) result end .,., -module_eval(<<'.,.,', 'parser.y', 480) +module_eval(<<'.,.,', 'parser.y', 488) def _reduce_116(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', 481) +module_eval(<<'.,.,', 'parser.y', 489) def _reduce_117(val, _values, result) result = [Lrama::Lexer::Token::InstantiateRule.new(s_value: val[0].s_value, location: @lexer.location, args: val[2])] result @@ -2127,7 +2136,7 @@ def _reduce_117(val, _values, result) # reduce 118 omitted -module_eval(<<'.,.,', 'parser.y', 484) +module_eval(<<'.,.,', 'parser.y', 492) def _reduce_119(val, _values, result) result = val[1].s_value result @@ -2138,7 +2147,7 @@ def _reduce_119(val, _values, result) # reduce 121 omitted -module_eval(<<'.,.,', 'parser.y', 491) +module_eval(<<'.,.,', 'parser.y', 499) def _reduce_122(val, _values, result) begin_c_declaration('\Z') @grammar.epilogue_first_lineno = @lexer.line + 1 @@ -2147,7 +2156,7 @@ def _reduce_122(val, _values, result) end .,., -module_eval(<<'.,.,', 'parser.y', 496) +module_eval(<<'.,.,', 'parser.y', 504) def _reduce_123(val, _values, result) end_c_declaration @grammar.epilogue = val[2].s_value @@ -2166,14 +2175,14 @@ def _reduce_123(val, _values, result) # reduce 128 omitted -module_eval(<<'.,.,', 'parser.y', 507) +module_eval(<<'.,.,', 'parser.y', 515) def _reduce_129(val, _values, result) result = [val[0]] result end .,., -module_eval(<<'.,.,', 'parser.y', 508) +module_eval(<<'.,.,', 'parser.y', 516) def _reduce_130(val, _values, result) result = val[0].append(val[1]) result @@ -2184,7 +2193,7 @@ def _reduce_130(val, _values, result) # reduce 132 omitted -module_eval(<<'.,.,', 'parser.y', 513) +module_eval(<<'.,.,', 'parser.y', 521) def _reduce_133(val, _values, result) result = Lrama::Lexer::Token::Ident.new(s_value: val[0]) result diff --git a/tool/lrama/lib/lrama/version.rb b/tool/lrama/lib/lrama/version.rb index 15ab009bd5ed01..ccd593f344f532 100644 --- a/tool/lrama/lib/lrama/version.rb +++ b/tool/lrama/lib/lrama/version.rb @@ -1,3 +1,3 @@ module Lrama - VERSION = "0.6.3".freeze + VERSION = "0.6.5".freeze end diff --git a/tool/lrama/template/bison/yacc.c b/tool/lrama/template/bison/yacc.c index 6145a95091c09c..2d6753c2829090 100644 --- a/tool/lrama/template/bison/yacc.c +++ b/tool/lrama/template/bison/yacc.c @@ -1145,7 +1145,12 @@ yydestruct (const char *yymsg, YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp<%= output.user_args %>); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YY_USE (yykind); + switch (yykind) + { +<%= output.symbol_actions_for_destructor -%> + default: + break; + } YY_IGNORE_MAYBE_UNINITIALIZED_END } diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb index 832e22324c6c02..cdaeff666832b4 100755 --- a/tool/rbinstall.rb +++ b/tool/rbinstall.rb @@ -549,47 +549,103 @@ def initialize(gemspec, srcdir, relative_base) end def collect - ruby_libraries.sort + requirable_features.sort + end + + private + + def features_from_makefile(makefile_path) + makefile = File.read(makefile_path) + + name = makefile[/^TARGET[ \t]*=[ \t]*((?:.*\\\n)*.*)/, 1] + return [] if name.nil? || name.empty? + + feature = makefile[/^DLLIB[ \t]*=[ \t]*((?:.*\\\n)*.*)/, 1] + feature = feature.sub("$(TARGET)", name) + + target_prefix = makefile[/^target_prefix[ \t]*=[ \t]*((?:.*\\\n)*.*)/, 1] + feature = File.join(target_prefix.delete_prefix("/"), feature) unless target_prefix.empty? + + Array(feature) end class Ext < self - def skip_install?(files) + def requirable_features # install ext only when it's configured - !File.exist?("#{$ext_build_dir}/#{relative_base}/Makefile") + return [] unless File.exist?(makefile_path) + + ruby_features + ext_features + end + + private + + def ruby_features + Dir.glob("**/*.rb", base: "#{makefile_dir}/lib") + end + + def ext_features + features_from_makefile(makefile_path) + end + + def makefile_path + "#{makefile_dir}/Makefile" end - def ruby_libraries - Dir.glob("lib/**/*.rb", base: "#{srcdir}/ext/#{relative_base}") + def makefile_dir + "#{root}/#{relative_base}" + end + + def root + File.expand_path($ext_build_dir, srcdir) end end class Lib < self - def skip_install?(files) - files.empty? + def requirable_features + ruby_features + ext_features end - def ruby_libraries + private + + def ruby_features gemname = File.basename(gemspec, ".gemspec") base = relative_base || gemname # for lib/net/net-smtp.gemspec if m = /.*(?=-(.*)\z)/.match(gemname) base = File.join(base, *m.to_a.select {|n| !base.include?(n)}) end - files = Dir.glob("lib/#{base}{.rb,/**/*.rb}", base: srcdir) + files = Dir.glob("#{base}{.rb,/**/*.rb}", base: root) if !relative_base and files.empty? # no files at the toplevel # pseudo gem like ruby2_keywords - files << "lib/#{gemname}.rb" + files << "#{gemname}.rb" end case gemname when "net-http" - files << "lib/net/https.rb" + files << "net/https.rb" when "optparse" - files << "lib/optionparser.rb" + files << "optionparser.rb" end files end + + def ext_features + loaded_gemspec = load_gemspec("#{root}/#{gemspec}") + extension = loaded_gemspec.extensions.first + return [] unless extension + + extconf = File.expand_path(extension, srcdir) + ext_build_dir = File.dirname(extconf) + makefile_path = "#{ext_build_dir}/Makefile" + return [] unless File.exist?(makefile_path) + + features_from_makefile(makefile_path) + end + + def root + "#{srcdir}/lib" + end end end end @@ -717,7 +773,7 @@ def load_gemspec(file, base = nil) "[" + files.join(", ") + "]" end code.gsub!(/IO\.popen\(.*git.*?\)/) do - "[" + files.join(", ") + "].each" + "[" + files.join(", ") + "] || itself" end spec = eval(code, binding, file) @@ -757,7 +813,7 @@ def install_default_gem(dir, srcdir, bindir) spec = load_gemspec("#{base}/#{src}") file_collector = RbInstall::Specs::FileCollector.for(srcdir, dir, src) files = file_collector.collect - if file_collector.skip_install?(files) + if files.empty? next end spec.files = files diff --git a/tool/test_for_warn_bundled_gems/test.sh b/tool/test_for_warn_bundled_gems/test.sh index ce714c7e13314f..ef5007f320ab77 100755 --- a/tool/test_for_warn_bundled_gems/test.sh +++ b/tool/test_for_warn_bundled_gems/test.sh @@ -2,30 +2,44 @@ echo "* Show warning require and LoadError" ruby test_warn_bundled_gems.rb +echo echo "* Show warning when bundled gems called as dependency" ruby test_warn_dependency.rb +echo echo "* Show warning sub-feature like bigdecimal/util" ruby test_warn_sub_feature.rb +echo echo "* Show warning dash gem like net/smtp" ruby test_warn_dash_gem.rb +echo echo "* Show warning when bundle exec with ruby and script" bundle exec ruby test_warn_bundle_exec.rb +echo echo "* Show warning when bundle exec with shebang's script" bundle exec ./test_warn_bundle_exec_shebang.rb +echo + +echo "* Show warning with bootsnap" +ruby test_warn_bootsnap.rb +echo + +echo "* Show warning with zeitwerk" +ruby test_warn_zeitwerk.rb +echo echo "* Don't show warning bundled gems on Gemfile" ruby test_no_warn_dependency.rb - -echo "* Don't show warning with bootsnap" -ruby test_no_warn_bootsnap.rb +echo echo "* Don't show warning with net/smtp when net-smtp on Gemfile" ruby test_no_warn_dash_gem.rb +echo echo "* Don't show warning bigdecimal/util when bigdecimal on Gemfile" ruby test_no_warn_sub_feature.rb +echo diff --git a/tool/test_for_warn_bundled_gems/test_no_warn_bootsnap.rb b/tool/test_for_warn_bundled_gems/test_warn_bootsnap.rb similarity index 100% rename from tool/test_for_warn_bundled_gems/test_no_warn_bootsnap.rb rename to tool/test_for_warn_bundled_gems/test_warn_bootsnap.rb diff --git a/tool/test_for_warn_bundled_gems/test_warn_zeitwerk.rb b/tool/test_for_warn_bundled_gems/test_warn_zeitwerk.rb new file mode 100644 index 00000000000000..d554a0e6756845 --- /dev/null +++ b/tool/test_for_warn_bundled_gems/test_warn_zeitwerk.rb @@ -0,0 +1,12 @@ +require "bundler/inline" + +gemfile do + source "https://rubygems.org" + gem "zeitwerk", require: false +end + +require "zeitwerk" +loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false) +loader.setup + +require 'csv' diff --git a/vm.c b/vm.c index 2dbf44bf97ea60..45c62eda5a9bfd 100644 --- a/vm.c +++ b/vm.c @@ -3423,10 +3423,7 @@ rb_execution_context_mark(const rb_execution_context_t *ec) if (ec->machine.stack_start && ec->machine.stack_end && ec != GET_EC() /* marked for current ec at the first stage of marking */ ) { - rb_gc_mark_machine_stack(ec); - rb_gc_mark_locations((VALUE *)&ec->machine.regs, - (VALUE *)(&ec->machine.regs) + - sizeof(ec->machine.regs) / (sizeof(VALUE))); + rb_gc_mark_machine_context(ec); } rb_gc_mark(ec->errinfo); diff --git a/vm_args.c b/vm_args.c index d1a7695c6e39cc..9df175eaa94a79 100644 --- a/vm_args.c +++ b/vm_args.c @@ -687,6 +687,9 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co rest_last = rb_hash_dup(rest_last); kw_flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT; + // Unset rest_dupped set by anon_rest as we may need to modify splat in this case + args->rest_dupped = false; + if (ignore_keyword_hash_p(rest_last, iseq, &kw_flag, &converted_keyword_hash)) { arg_rest_dup(args); rb_ary_pop(args->rest); @@ -725,8 +728,9 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co kw_flag &= ~(VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT); } else { - if (!(kw_flag & VM_CALL_KW_SPLAT_MUT)) { + if (!(kw_flag & VM_CALL_KW_SPLAT_MUT) && !ISEQ_BODY(iseq)->param.flags.has_kw) { converted_keyword_hash = rb_hash_dup(converted_keyword_hash); + kw_flag |= VM_CALL_KW_SPLAT_MUT; } if (last_arg != converted_keyword_hash) { diff --git a/vm_backtrace.c b/vm_backtrace.c index 9b256fa4e80a83..11b26adbf49781 100644 --- a/vm_backtrace.c +++ b/vm_backtrace.c @@ -287,15 +287,14 @@ location_label(rb_backtrace_location_t *loc) * 1.times do * puts caller_locations(0).first.label * end - * * end * end * * The result of calling +foo+ is this: * - * label: foo - * label: block in foo - * label: block (2 levels) in foo + * foo + * block in foo + * block (2 levels) in foo * */ static VALUE @@ -315,9 +314,28 @@ location_base_label(rb_backtrace_location_t *loc) } /* - * Returns the base label of this frame. + * Returns the base label of this frame, which is usually equal to the label, + * without decoration. + * + * Consider the following example: + * + * def foo + * puts caller_locations(0).first.base_label + * + * 1.times do + * puts caller_locations(0).first.base_label + * + * 1.times do + * puts caller_locations(0).first.base_label + * end + * end + * end + * + * The result of calling +foo+ is this: * - * Usually same as #label, without decoration. + * foo + * foo + * foo */ static VALUE location_base_label_m(VALUE self) @@ -571,6 +589,13 @@ is_internal_location(const rb_control_frame_t *cfp) return strncmp(prefix, RSTRING_PTR(file), prefix_len) == 0; } +static bool +is_rescue_or_ensure_frame(const rb_control_frame_t *cfp) +{ + enum rb_iseq_type type = ISEQ_BODY(cfp->iseq)->type; + return type == ISEQ_TYPE_RESCUE || type == ISEQ_TYPE_ENSURE; +} + static void bt_update_cfunc_loc(unsigned long cfunc_counter, rb_backtrace_location_t *cfunc_loc, const rb_iseq_t *iseq, const VALUE *pc) { @@ -600,6 +625,7 @@ rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_fram VALUE btobj = Qnil; rb_backtrace_location_t *loc = NULL; unsigned long cfunc_counter = 0; + bool skip_next_frame = FALSE; // In the case the thread vm_stack or cfp is not initialized, there is no backtrace. if (end_cfp == NULL) { @@ -641,18 +667,21 @@ rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_fram if (start_frame > 0) { start_frame--; } - else if (!skip_internal || !is_internal_location(cfp)) { - const rb_iseq_t *iseq = cfp->iseq; - const VALUE *pc = cfp->pc; - loc = &bt->backtrace[bt->backtrace_size++]; - RB_OBJ_WRITE(btobj, &loc->cme, rb_vm_frame_method_entry(cfp)); - RB_OBJ_WRITE(btobj, &loc->iseq, iseq); - loc->pc = pc; - bt_update_cfunc_loc(cfunc_counter, loc-1, iseq, pc); - if (do_yield) { - bt_yield_loc(loc - cfunc_counter, cfunc_counter+1, btobj); + else if (!(skip_internal && is_internal_location(cfp))) { + if (!skip_next_frame) { + const rb_iseq_t *iseq = cfp->iseq; + const VALUE *pc = cfp->pc; + loc = &bt->backtrace[bt->backtrace_size++]; + RB_OBJ_WRITE(btobj, &loc->cme, rb_vm_frame_method_entry(cfp)); + RB_OBJ_WRITE(btobj, &loc->iseq, iseq); + loc->pc = pc; + bt_update_cfunc_loc(cfunc_counter, loc-1, iseq, pc); + if (do_yield) { + bt_yield_loc(loc - cfunc_counter, cfunc_counter+1, btobj); + } + cfunc_counter = 0; } - cfunc_counter = 0; + skip_next_frame = is_rescue_or_ensure_frame(cfp); } } } @@ -671,9 +700,12 @@ rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_fram } } + // When a backtrace entry corresponds to a method defined in C (e.g. rb_define_method), the reported file:line + // is the one of the caller Ruby frame, so if the last entry is a C frame we find the caller Ruby frame here. if (cfunc_counter > 0) { for (; cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) { - if (cfp->iseq && cfp->pc && (!skip_internal || !is_internal_location(cfp))) { + if (cfp->iseq && cfp->pc && !(skip_internal && is_internal_location(cfp))) { + VM_ASSERT(!skip_next_frame); // ISEQ_TYPE_RESCUE/ISEQ_TYPE_ENSURE should have a caller Ruby ISEQ, not a cfunc bt_update_cfunc_loc(cfunc_counter, loc, cfp->iseq, cfp->pc); RB_OBJ_WRITTEN(btobj, Qundef, cfp->iseq); if (do_yield) { diff --git a/vm_core.h b/vm_core.h index e06fb0b16b2427..54a65054ec54a1 100644 --- a/vm_core.h +++ b/vm_core.h @@ -1071,6 +1071,10 @@ struct rb_execution_context_struct { VALUE *stack_end; size_t stack_maxsize; RUBY_ALIGNAS(SIZEOF_VALUE) jmp_buf regs; + +#ifdef RUBY_ASAN_ENABLED + void *asan_fake_stack_handle; +#endif } machine; }; @@ -1191,11 +1195,6 @@ typedef struct rb_thread_struct { void **specific_storage; struct rb_ext_config ext_config; - -#ifdef RUBY_ASAN_ENABLED - void *asan_fake_stack_handle; -#endif - } rb_thread_t; static inline unsigned int @@ -1909,7 +1908,7 @@ void rb_vm_register_special_exception_str(enum ruby_special_exceptions sp, VALUE #define rb_vm_register_special_exception(sp, e, m) \ rb_vm_register_special_exception_str(sp, e, rb_usascii_str_new_static((m), (long)rb_strlen_lit(m))) -void rb_gc_mark_machine_stack(const rb_execution_context_t *ec); +void rb_gc_mark_machine_context(const rb_execution_context_t *ec); void rb_vm_rewrite_cref(rb_cref_t *node, VALUE old_klass, VALUE new_klass, rb_cref_t **new_cref_ptr); diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 6963aca48e1b1e..1d9955260b2322 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -7095,15 +7095,15 @@ fn gen_send_iseq( } match block_arg_type { - Some(Type::Nil) => { + Some(BlockArg::Nil) => { // We have a nil block arg, so let's pop it off the args asm.stack_pop(1); } - Some(Type::BlockParamProxy) => { + Some(BlockArg::BlockParamProxy) => { // We don't need the actual stack value asm.stack_pop(1); } - Some(Type::TProc) => { + Some(BlockArg::TProc) => { // Place the proc as the block handler. We do this early because // the block arg being at the top of the stack gets in the way of // rest param handling later. Also, since there are C calls that @@ -7136,7 +7136,6 @@ fn gen_send_iseq( None => { // Nothing to do } - _ => unreachable!(), } if kw_splat { @@ -7396,9 +7395,9 @@ fn gen_send_iseq( } else if let Some(captured_opnd) = captured_opnd { let ep_opnd = asm.load(Opnd::mem(64, captured_opnd, SIZEOF_VALUE_I32)); // captured->ep SpecVal::PrevEPOpnd(ep_opnd) - } else if let Some(Type::TProc) = block_arg_type { + } else if let Some(BlockArg::TProc) = block_arg_type { SpecVal::BlockHandler(Some(BlockHandler::AlreadySet)) - } else if let Some(Type::BlockParamProxy) = block_arg_type { + } else if let Some(BlockArg::BlockParamProxy) = block_arg_type { SpecVal::BlockHandler(Some(BlockHandler::BlockParamProxy)) } else { SpecVal::BlockHandler(block) @@ -7942,12 +7941,22 @@ fn exit_if_has_rest_and_optional_and_block(asm: &mut Assembler, iseq_has_rest: b ) } +#[derive(Clone, Copy)] +enum BlockArg { + Nil, + /// A special sentinel value indicating the block parameter should be read from + /// the current surrounding cfp + BlockParamProxy, + /// A proc object. Could be an instance of a subclass of ::rb_cProc + TProc, +} + #[must_use] fn exit_if_unsupported_block_arg_type( jit: &mut JITState, asm: &mut Assembler, supplying_block_arg: bool -) -> Option> { +) -> Option> { let block_arg_type = if supplying_block_arg { asm.ctx.get_opnd_type(StackOpnd(0)) } else { @@ -7956,16 +7965,15 @@ fn exit_if_unsupported_block_arg_type( }; match block_arg_type { - Type::Nil | Type::BlockParamProxy => { - // We'll handle this later - Some(Some(block_arg_type)) - } + // We'll handle Nil and BlockParamProxy later + Type::Nil => Some(Some(BlockArg::Nil)), + Type::BlockParamProxy => Some(Some(BlockArg::BlockParamProxy)), _ if { let sample_block_arg = jit.peek_at_stack(&asm.ctx, 0); unsafe { rb_obj_is_proc(sample_block_arg) }.test() } => { // Speculate that we'll have a proc as the block arg - Some(Some(Type::TProc)) + Some(Some(BlockArg::TProc)) } _ => { gen_counter_incr(asm, Counter::send_iseq_block_arg_type); diff --git a/yjit/src/core.rs b/yjit/src/core.rs index 90e6490997497c..000e0c0be03314 100644 --- a/yjit/src/core.rs +++ b/yjit/src/core.rs @@ -60,13 +60,11 @@ pub enum Type { TArray, // An object with the T_ARRAY flag set, possibly an rb_cArray THash, // An object with the T_HASH flag set, possibly an rb_cHash - TProc, // A proc object. Could be an instance of a subclass of ::rb_cProc - BlockParamProxy, // A special sentinel value indicating the block parameter should be read from // the current surrounding cfp // The context currently relies on types taking at most 4 bits (max value 15) - // to encode, so if we add any more, we will need to refactor the context, + // to encode, so if we add two more, we will need to refactor the context, // or we could remove HeapSymbol, which is currently unused. } @@ -113,8 +111,6 @@ impl Type { RUBY_T_ARRAY => Type::TArray, RUBY_T_HASH => Type::THash, RUBY_T_STRING => Type::TString, - #[cfg(not(test))] - RUBY_T_DATA if unsafe { rb_obj_is_proc(val).test() } => Type::TProc, _ => Type::UnknownHeap, } } @@ -159,7 +155,6 @@ impl Type { Type::TString => true, Type::CString => true, Type::BlockParamProxy => true, - Type::TProc => true, _ => false, } } @@ -195,7 +190,6 @@ impl Type { Type::THash => Some(RUBY_T_HASH), Type::ImmSymbol | Type::HeapSymbol => Some(RUBY_T_SYMBOL), Type::TString | Type::CString => Some(RUBY_T_STRING), - Type::TProc => Some(RUBY_T_DATA), Type::Unknown | Type::UnknownImm | Type::UnknownHeap => None, Type::BlockParamProxy => None, } diff --git a/yjit/yjit.mk b/yjit/yjit.mk index 1a8a3b88699c31..137085376d1ac1 100644 --- a/yjit/yjit.mk +++ b/yjit/yjit.mk @@ -23,7 +23,7 @@ YJIT_LIB_TOUCH = touch $@ ifeq ($(YJIT_SUPPORT),yes) $(YJIT_LIBS): $(YJIT_SRC_FILES) $(ECHO) 'building Rust YJIT (release mode)' - $(Q) $(RUSTC) $(YJIT_RUSTC_ARGS) + +$(Q) $(RUSTC) $(YJIT_RUSTC_ARGS) $(YJIT_LIB_TOUCH) else ifeq ($(YJIT_SUPPORT),no) $(YJIT_LIBS): @@ -32,7 +32,7 @@ $(YJIT_LIBS): else ifeq ($(YJIT_SUPPORT),$(filter dev dev_nodebug stats,$(YJIT_SUPPORT))) $(YJIT_LIBS): $(YJIT_SRC_FILES) $(ECHO) 'building Rust YJIT ($(YJIT_SUPPORT) mode)' - $(Q)$(CHDIR) $(top_srcdir)/yjit && \ + +$(Q)$(CHDIR) $(top_srcdir)/yjit && \ CARGO_TARGET_DIR='$(CARGO_TARGET_DIR)' \ CARGO_TERM_PROGRESS_WHEN='never' \ $(CARGO) $(CARGO_VERBOSE) build $(CARGO_BUILD_ARGS)